For the EPRI’s WET Forum

Query and load IM3 data

Run this query_im3_scen("epri") only once to query from remote IM3 databases. Once a .dat file is created, we can load the existing project data by loadProject(proj = "im3scen_epri.dat").

# query the data
# im3_epri <- query_im3_scen("epri")
# load the data
im3_epri <- loadProject(proj = paste0("../", data_dir, "im3scen_epri.dat"))
# scenarios and queries 
listScenarios(im3_epri)
[1] "rcp45cooler_ssp3" "rcp45cooler_ssp5" "rcp45hotter_ssp3" "rcp45hotter_ssp5" "rcp85cooler_ssp3"
[6] "rcp85cooler_ssp5" "rcp85hotter_ssp3" "rcp85hotter_ssp5"
listQueries(im3_epri)
 [1] "resource supply curves"                                    
 [2] "resource production"                                       
 [3] "resource production by tech and vintage"                   
 [4] "basin level available runoff"                              
 [5] "total groundwater available"                               
 [6] "water withdrawals by water mapping source"                 
 [7] "water withdrawals by tech"                                 
 [8] "water withdrawals by state, sector, basin (includes desal)"
 [9] "water withdrawals by water source (runoff vs. groundwater)"
[10] "elec energy input by elec gen tech and cooling tech"       
[11] "elec water withdrawals by gen tech and cooling tech"       
[12] "elec gen by gen tech and cooling tech (incl cogen)"        
[13] "elec energy input by elec gen tech"                        
[14] "elec gen by gen tech and cooling tech"                     
[15] "elec water withdrawals by gen tech"                        
[16] "elec td inputs and outputs"                                
[17] "elec consumption by demand sector"                         

Water Sankey

Overall required information

  • water availability by source (e.g., groundwater, surface water, desalination)
  • water use by categories (e.g., agriculture, industry, domestic, power etc)
  • water use by end-use sectors (e.g., crops, industry, electricity etc)

GCAM queries

  • availability
    • resource supply curves
    • basin level available runoff
    • total runoff available
    • total groundwater available
  • use by source
    • resource production
    • resource production by tech and vintage
    • water withdrawals by water source (runoff vs. groundwater)
  • use by region/basin
    • water withdrawals by region
  • use by category
    • water withdrawals by water mapping source
    • water withdrawals by tech
    • water withdrawals by tech (all elec)
    • water withdrawals by state, sector, basin (includes desal)
# get queries 
# availability 
resourceSupplyCurves <- getQuery(im3_epri, "resource supply curves") %>% filter_CONUSregions()
basinLevelAvailableRunoff <- getQuery(im3_epri, "basin level available runoff") %>% filter_CONUSregions() 
# totalRunoffAvailable <- getQuery(im3_epri, "total runoff available") %>% filter_CONUSregions()
totalGroundwaterAvailable <- getQuery(im3_epri, "total groundwater available") %>% filter_CONUSregions()
# production 
resourceProduction <- getQuery(im3_epri, "resource production") %>% filter_CONUSregions()
resourceProductionByTechVintage <- getQuery(im3_epri, "resource production by tech and vintage") %>% filter_CONUSregions()
waterWithdrawalsByWaterSource <- getQuery(im3_epri, "water withdrawals by water source (runoff vs. groundwater)") %>% filter_CONUSregions()
# use by region/basin 
# waterWithdrawalsByRegion <- getQuery(im3_epri, "water withdrawals by region") %>% filter_CONUSregions()
waterWithdrawalsByStateSectorBasin <- getQuery(im3_epri, "water withdrawals by state, sector, basin (includes desal)") %>% filter_CONUSregions()
# use by category 
waterWithdrawalsByWaterMappingSource <- getQuery(im3_epri, "water withdrawals by water mapping source") %>% filter_CONUSregions()
waterWithdrawalsByTech <- getQuery(im3_epri, "water withdrawals by tech") %>% filter_CONUSregions()
# waterWithdrawalsByTechAllElec <- getQuery(im3_epri, "water withdrawals by tech (all elec)") %>% filter_CONUSregions()
data_tables_water <- list(
  "resourceSupplyCurves" = resourceSupplyCurves,
  "basinLevelAvailableRunoff" = basinLevelAvailableRunoff,
  # "totalRunoffAvailable" = totalRunoffAvailable,
  "totalGroundwaterAvailable" = totalGroundwaterAvailable,
  "resourceProduction" = resourceProduction,
  "resourceProductionByTechVintage" = resourceProductionByTechVintage,
  "waterWithdrawalsByWaterSource" = waterWithdrawalsByWaterSource,
  # "waterWithdrawalsByRegion" = waterWithdrawalsByRegion,
  "waterWithdrawalsByStateSectorBasin" = waterWithdrawalsByStateSectorBasin,
  "waterWithdrawalsByWaterMappingSource" = waterWithdrawalsByWaterMappingSource,
  "waterWithdrawalsByTech" = waterWithdrawalsByTech
  # "waterWithdrawalsByTechAllElec" = waterWithdrawalsByTechAllElec
)

# print column names of each datatable
lapply(data_tables_water, function(x) colnames(x))
$resourceSupplyCurves
[1] "Units"       "scenario"    "region"      "resource"    "subresource" "grade"       "year"       
[8] "value"      

$basinLevelAvailableRunoff
[1] "Units"       "scenario"    "region"      "basin"       "subresource" "year"        "value"      

$totalGroundwaterAvailable
[1] "Units"       "scenario"    "region"      "resource"    "subresource" "grade"       "year"       
[8] "value"      

$resourceProduction
[1] "Units"    "scenario" "region"   "resource" "year"     "value"   

$resourceProductionByTechVintage
[1] "Units"       "scenario"    "region"      "resource"    "subresource" "technology"  "year"       
[8] "value"      

$waterWithdrawalsByWaterSource
[1] "Units"       "scenario"    "region"      "resource"    "subresource" "year"        "value"      

$waterWithdrawalsByStateSectorBasin
[1] "Units"      "scenario"   "region"     "sector"     "subsector"  "technology" "year"       "value"     

$waterWithdrawalsByWaterMappingSource
[1] "Units"    "scenario" "region"   "input"    "year"     "value"   

$waterWithdrawalsByTech
[1] "Units"      "scenario"   "region"     "sector"     "subsector"  "technology" "year"       "value"     
# print the first few rows of each datatable
lapply(data_tables_water, function(x) (x))
$resourceSupplyCurves

$basinLevelAvailableRunoff

$totalGroundwaterAvailable

$resourceProduction

$resourceProductionByTechVintage

$waterWithdrawalsByWaterSource

$waterWithdrawalsByStateSectorBasin

$waterWithdrawalsByWaterMappingSource

$waterWithdrawalsByTech
NA

Let’s process each piece to prepare the format of: scenario, source, target, year, value. Scenario and year could be filtered for each Sankey.

Water Availability

unique(resourceSupplyCurves$resource)
 [1] "onshore wind resource"                      "geothermal"                                
 [3] "coal"                                       "crude oil"                                 
 [5] "natural gas"                                "unconventional oil"                        
 [7] "traditional biomass"                        "Residue"                                   
 [9] "Scavenging_Other_Rsrc"                      "uranium"                                   
[11] "onshore carbon-storage"                     "Atlantic Ocean Seaboard_water withdrawals" 
[13] "Churchill_water withdrawals"                "Fraser_water withdrawals"                  
[15] "Great Lakes_water withdrawals"              "Hudson Bay Coast_water withdrawals"        
[17] "Mackenzie_water withdrawals"                "Northwest Territories_water withdrawals"   
[19] "Saskatchewan-Nelson_water withdrawals"      "St Lawrence_water withdrawals"             
[21] "Baja California_water withdrawals"          "Grijalva-Usumacinta_water withdrawals"     
[23] "Isthmus of Tehuantepec_water withdrawals"   "Mexico-Interior_water withdrawals"         
[25] "Mexico-Northwest Coast_water withdrawals"   "North Gulf_water withdrawals"              
[27] "Pacific Central Coast_water withdrawals"    "Papaloapan_water withdrawals"              
[29] "Rio Balsas_water withdrawals"               "Rio Lerma_water withdrawals"               
[31] "Rio Verde_water withdrawals"                "Yucatan Peninsula_water withdrawals"       
[33] "Arkansas White Red_water withdrawals"       "California River_water withdrawals"        
[35] "Great_water withdrawals"                    "Hawaii_water withdrawals"                  
[37] "Lower Colorado River_water withdrawals"     "Lower Mississippi River_water withdrawals" 
[39] "Mid Atlantic_water withdrawals"             "Missouri River_water withdrawals"          
[41] "New England_water withdrawals"              "Ohio River_water withdrawals"              
[43] "Pacific Northwest_water withdrawals"        "Pacific and Arctic Coast_water withdrawals"
[45] "Rio Grande River_water withdrawals"         "South Atlantic Gulf_water withdrawals"     
[47] "Tennessee River_water withdrawals"          "Texas Gulf Coast_water withdrawals"        
[49] "Upper Colorado River_water withdrawals"     "Upper Mississippi_water withdrawals"       
unique(resourceSupplyCurves$subresource)
 [1] "onshore wind resource"  "hydrothermal"           "coal"                   "crude oil"             
 [5] "natural gas"            "unconventional oil"     "traditional biomass"    "Residue"               
 [9] "Scavenging_Other"       "uranium"                "onshore carbon-storage" "groundwater"           
[13] "runoff"                
resourceSupplyCurves_water <- resourceSupplyCurves %>% filter(subresource %in% c("groundwater", "runoff")) %>% 
  filter(grade != "grade hist") %>% #exclude historical usage
  filter_basin_resource() %>%
  group_by(scenario, resource, subresource, year) %>% 
  summarise(value = sum(value)) %>% ungroup() %>% 
  remove_water_withdrawals_string() %>% 
  select(scenario, source = resource, target = subresource, year, value)
`summarise()` has grouped output by 'scenario', 'resource', 'subresource'. You can override using the `.groups` argument.
datatable(resourceSupplyCurves_water, filter = "top") 
plot_sankey(resourceSupplyCurves_water, "Water Availability by Basin and Resource Type")
NA

Total resource availability doesn’t change over time. This doesn’t look right because basin level available runoff (which uses max-annual-subresource instead of summing all grades) is much more and changes over time.

<resourceQuery title="total groundwater available">
    <axis1 name="grade">grade</axis1>
    <axis2 name="Year">available</axis2>
    <xPath buildList="true" dataName="output" group="false" sumAll="true">*[@type='resource']/*[@type='subresource' and @name='groundwater']/grade/available/node()</xPath>
</resourceQuery>

basinLevelAvailableRunoff is the one that uses max-annual-subresource instead of summing all grades

<resourceQuery title="basin level available runoff">
    <axis1 name="Basin">resource[@name]</axis1>
    <axis2 name="Year">max-annual-subresource[@year]</axis2>
    <xPath buildList="true" dataName="input" group="false" sumAll="false">*[@type = 'resource' and contains(@name, 'water withdrawals')]/*[@type = 'subresource' and contains(@name, 'runoff')]/max-annual-subresource/node()</xPath>
</resourceQuery>

Let’s use a combination of basinLevelAvailableRunoff and totalGroundwaterAvailable to get the total water availability by basin and year.

This looks better! Let’s move to water withdrawals.

Water Withdrawals

Let’s start by quantifying water withdrawals by water source (runoff vs. groundwater) for each basin.

  • resourceProduction gives ALL resources, would need to filter by _water withdrawals. BUT this will give TOTAL basin level production (as basins are resources) and not by water source (runoff vs. groundwater) which are subresources.
  • resourceProductionByTechVintage is the most detailed resource query, with information for regions, resources (water withdrawals), subresources (runoff, groundwater), production by year.

But let’s use a ready-made query waterWithdrawalsByWaterSource which gives water withdrawals by water source (runoff vs. groundwater) for each basin (resource).

  • However, this still doesn’t have desalination. resourceProduction has desalination, but on the USA level. We will need to get desalination from waterWithdrawalsByStateSectorBasin.
# prepare desalination tables 
desalByBasin <- waterWithdrawalsByStateSectorBasin %>% 
    filter(region != "USA") %>% 
    filter(technology == "desalination") %>%
    filter_CONUSregions(subsector, basins_conus_resource) %>% 
    group_by(scenario, subsector, technology, year) %>%
    summarise(value = sum(value)) %>% ungroup() %>%
    select(scenario, source = technology, target = subsector, year, value)
`summarise()` has grouped output by 'scenario', 'subsector', 'technology'. You can override using the `.groups` argument.
desalByUseCategory <- waterWithdrawalsByStateSectorBasin %>% 
    filter(region != "USA") %>% 
    filter(technology == "desalination") %>% 
    filter_CONUSregions(subsector, basins_conus_resource) %>% 
    group_by(scenario, sector, technology, year) %>%
    summarise(value = sum(value)) %>% ungroup() %>%
    select(scenario, source = technology, target = sector, year, value)
`summarise()` has grouped output by 'scenario', 'sector', 'technology'. You can override using the `.groups` argument.
desalByState <- waterWithdrawalsByStateSectorBasin %>%
    filter(region != "USA") %>% 
    filter(technology == "desalination") %>% 
    filter_CONUSregions(subsector, basins_conus_resource) %>%   
    group_by(scenario, region, technology, year) %>%
    summarise(value = sum(value)) %>% ungroup() %>%
    select(scenario, source = technology, target = region, year, value)
`summarise()` has grouped output by 'scenario', 'region', 'technology'. You can override using the `.groups` argument.
plot_sankey(rbind(totalWaterAvailability, desalByBasin), "Total Water Availability by Basin and Resource Type")
df_waterWithdrawalsByWaterSource <- rbind(
  waterWithdrawalsByWaterSource %>% 
    filter_basin_resource() %>% 
    remove_water_withdrawals_string() %>%
    select(scenario, source = subresource, target = resource, year, value)
  , 
  desalByBasin
  )

datatable(df_waterWithdrawalsByWaterSource, filter = "top")
plot_sankey(df_waterWithdrawalsByWaterSource, "Water Withdrawals by Basin and Water Source")
NA
  • Only 7 basins use groundwater in 2050 example above.

Water Withdrawals by State, Sector, and Basin


df_waterWithdrawalsByStateSectorBasin <- waterWithdrawalsByStateSectorBasin %>% 
  filter(region != "USA") %>% # exclude USA level data because it aggregated up from basin level data, but lacks the technology detail (name of the basin here)
  filter_CONUSregions(technology, basins_conus_resource) %>% # not sure why nonCONUS basins have crept in here at the technology level, but remove them 
  filter(technology != "desalination") %>% # we have desalination at the basin level in the previous plot 
  replace_after_irr_string() %>% # if this is removed, each basin will supply to it's own irrigation demand
  group_by(scenario, sector, technology, year) %>%
  summarise(value = sum(value)) %>% ungroup() %>%
  select(scenario, source = technology, target = sector, year, value)
`summarise()` has grouped output by 'scenario', 'sector', 'technology'. You can override using the `.groups` argument.
datatable(df_waterWithdrawalsByStateSectorBasin, filter = "top")
plot_sankey(df_waterWithdrawalsByStateSectorBasin, "Water Withdrawals by Use Category and Basin")

# let's try to piece this with waterWithdrawalsByWaterSource to the the water source type, basin, water use type flow
plot_sankey(rbind(df_waterWithdrawalsByStateSectorBasin, df_waterWithdrawalsByWaterSource), "Water Withdrawals by Use Category and Basin")
NA

TODO: Q: What is going on with Great Lakes? Why is it showing up in the water withdrawals but not in the water availability?

# exclude great lakes for now 
# we brought it back by borrowing from Canada. 
# df_waterWithdrawalsByStateSectorBasin <- df_waterWithdrawalsByStateSectorBasin %>% filter(source != "Great Lakes")

# plot_sankey(rbind(df_waterWithdrawalsByStateSectorBasin, df_waterWithdrawalsByWaterSource), "Water Withdrawals by Use Category and Basin")

Detailed Water Use

Let’s develop the water use categories further.

  • both waterWithdrawalsByTech and waterWithdrawalsByTechAllElec are the same queries.
  • get short basin names unique((waterWithdrawalsByTech_watCat %>% filter(grepl("biomassTree", subsector)))$subsector)
waterWithdrawalsByTech_watCat <- waterWithdrawalsByTech %>% map_water_use_to_categories() %>% filter_CONUSregions(region, states_conus)

watcategory_sector_use <- waterWithdrawalsByTech_watCat %>% 
  group_by(scenario, sector, watcategory, year) %>%
  summarise(value = sum(value)) %>% ungroup() %>%
  select(scenario, source = watcategory, target = sector, year, value)
`summarise()` has grouped output by 'scenario', 'sector', 'watcategory'. You can override using the `.groups` argument.
plot_sankey(rbind(df_waterWithdrawalsByStateSectorBasin, df_waterWithdrawalsByWaterSource, watcategory_sector_use), "Water Withdrawals by Use Category and Basin")

# use by subsector: same plot as previous after aggregation 
# watcategory_subsector_use <- waterWithdrawalsByTech_watCat %>% 
#   remove_GLUnames(subsector) %>% 
#   group_by(scenario, subsector, watcategory, year) %>%
#   summarise(value = sum(value)) %>% ungroup() %>%
#   select(scenario, source = watcategory, target = subsector, year, value)

# this is essentially the same as the previous plot
# plot_sankey(rbind(df_waterWithdrawalsByStateSectorBasin, df_waterWithdrawalsByWaterSource, watcategory_subsector_use), "Water Withdrawals by Use Category and Basin")
# expand electricity water use 
watcategory_subsector_use <- waterWithdrawalsByTech_watCat %>% 
  filter(sector == "electricity") %>%
  # remove_GLUnames(subsector) %>%
  group_by(scenario, sector, subsector, year) %>%
  summarise(value = sum(value)) %>% ungroup() %>%
  select(scenario, source = sector, target = subsector, year, value)
`summarise()` has grouped output by 'scenario', 'sector', 'subsector'. You can override using the `.groups` argument.
plot_sankey(rbind(df_waterWithdrawalsByStateSectorBasin, df_waterWithdrawalsByWaterSource, watcategory_sector_use, watcategory_subsector_use), "Water Withdrawals by Use Category and Basin")

Further technology level disaggregation for electricity water use

waterEnduseByTech <- waterWithdrawalsByTech_watCat %>% 
  filter(sector == "electricity") %>%
  clean_cooling_tech("technology", cooling_techs, cooling_techs_years) %>% 
  group_by(scenario, subsector, technology, year) %>%
  summarise(value = sum(value)) %>% ungroup() %>%
  select(scenario, source = subsector, target = technology, year, value)
`summarise()` has grouped output by 'scenario', 'subsector', 'technology'. You can override using the `.groups` argument.
plot_sankey(rbind(df_waterWithdrawalsByStateSectorBasin, df_waterWithdrawalsByWaterSource, watcategory_sector_use, watcategory_subsector_use, waterEnduseByTech), "Water Use by Source, Basin, Category, Sector, and Technology, and Basin")
NA

Water Requirement for Hydro

# add water requirement for hydro in the water diagram 
# ideally use hydro generation and create a water flow dynamically for all scenarios all years using the 3060 km3/EJ (853 MG/BBTU) coefficient 
# but right now, I am just going to create a single value

# hydro water requirement 

plot_sankey(rbind(df_waterWithdrawalsByStateSectorBasin, df_waterWithdrawalsByWaterSource, watcategory_sector_use, 
                  watcategory_subsector_use %>% 
                    # add hydro for rcp45cooler_ssp3 scenario and year 2050
                    add_row(scenario = "rcp45cooler_ssp3", source = "electricity", target = "hydro", year = 2050, value = 0.995 * 3060),
                  waterEnduseByTech) %>% rename_water_use_categories() %>% 
              mutate(source = ifelse(source == "runoff", "surface water", source)) %>% 
              mutate(target = ifelse(target == "industry", "industry (elec excluded)", target)),
            "Water Use by Source, Basin, Category, Sector, and Technology, and Basin")
  
plot_sankey(rbind(df_waterWithdrawalsByStateSectorBasin, df_waterWithdrawalsByWaterSource, watcategory_sector_use, 
                  watcategory_subsector_use %>% 
                    # add hydro for rcp45cooler_ssp3 scenario and year 2050
                    add_row(scenario = "rcp45cooler_ssp3", source = "electricity", target = "hydro", year = 2050, value = 0.995 * 3060 * 1e-3),
                  waterEnduseByTech) %>% rename_water_use_categories() %>% 
              mutate(source = ifelse(source == "runoff", "surface water", source)) %>% 
              mutate(target = ifelse(target == "industry", "industry (elec excluded)", target)),
            "Water Use by Source, Basin, Category, Sector, and Technology, and Basin")
  

# TODO: 
# labels
# time
# scenarios
# industry (elec excluded)
# relabel td sectors 
# runoff = surface water 
# annotations for levels (basins: HUC2)
# can colors the map as the plotly basins 
# avoid repeating colors
elecGenByGenTechCoolingTech_gUSA <- getQuery(im3_epri, "elec gen by gen tech and cooling tech (incl cogen)") %>% filter_CONUSregions()
elecGenByGenTechCoolingTech <- getQuery(im3_epri, "elec gen by gen tech and cooling tech") %>% filter_CONUSregions()
hydro_water_req <- elecGenByGenTechCoolingTech %>%
    filter(subsector == "hydro") %>%
    group_by(scenario, subsector, output, year) %>%
    summarise(value = sum(value)) %>% ungroup() %>% 
  mutate(source = "water_td_elec_W",
         hydro_water_req = value * 3060 * 1e-3) %>%
  select(scenario, source, target = subsector, year, value = hydro_water_req)
`summarise()` has grouped output by 'scenario', 'subsector', 'output'. You can override using the `.groups` argument.

Water Diagram for USA

# remove basins and electricity aggregations (only keep technologies)

# 1. prepare resources 

desal_totalUSA <- waterWithdrawalsByStateSectorBasin %>% 
    filter(region != "USA") %>% 
    filter(technology == "desalination") %>% 
    group_by(scenario, sector, technology, year) %>%
    summarise(value = sum(value)) %>% ungroup() %>%
    select(scenario, source = technology, target = sector, year, value)
`summarise()` has grouped output by 'scenario', 'sector', 'technology'. You can override using the `.groups` argument.
# create surface to groundwater shares by basin and apply those to use categories to determine amount of surface and groundwater used for each demand 
# 
# this calculates availabilty shares (which are not really relevant becasue we need withdrawal shares)
# totalWaterAvailability_USA <- rbind(
#   basinLevelAvailableRunoff %>% filter_basin_resource(basin) %>% remove_water_withdrawals_string(basin) %>% 
#     # we may have to switch the source and target here to start from water sources and go to basins
#     select(scenario, target = basin, source = subresource, year, value),
#   totalGroundwaterAvailable %>% 
#     filter_basin_resource() %>% remove_water_withdrawals_string() %>% 
#     filter(grade != "grade hist") %>% 
#     group_by(scenario, resource, subresource, year) %>%
#     summarise(value = sum(value)) %>% ungroup() %>%
#     select(scenario, target = resource, source = subresource, year, value)
# ) %>% group_by(scenario, source, year) %>%
#     summarise(value = sum(value)) %>% ungroup() 


waterWithdrawalsByWaterSource_shares_bybasin <- waterWithdrawalsByWaterSource %>% 
  filter_basin_resource() %>%
  remove_water_withdrawals_string() %>%
  group_by(scenario, region, resource, year) %>% mutate(share = value / sum(value)) %>% ungroup()

datatable(waterWithdrawalsByWaterSource_shares_bybasin, filter = "top")


waterWithdrawalsByStateSectorBasin_source <- waterWithdrawalsByStateSectorBasin %>% 
  # filter(scenario == "rcp85cooler_ssp5", year == "2050", sector == "water_td_an_W") %>%
  filter(region != "USA") %>% # exclude USA level data because it aggregated up from basin level data, but lacks the technology detail (name of the basin here)
  filter_CONUSregions(technology, basins_conus_resource) %>% # not sure why nonCONUS basins have crept in here at the technology level, but remove them 
  filter(technology != "desalination") %>% # we have desalination at the basin level in the previous plot 
  replace_after_irr_string() %>% # if this is removed, each basin will supply to it's own irrigation demand
  group_by(scenario, sector, technology, year) %>%
  summarise(value = sum(value)) %>% ungroup() %>%
  select(scenario, source = technology, target = sector, year, demand_withdraw = value) %>% 
  left_join(waterWithdrawalsByWaterSource_shares_bybasin, by = c("scenario", "source" = "resource", "year")) %>% 
  mutate(source_disagg = demand_withdraw * share) 
`summarise()` has grouped output by 'scenario', 'sector', 'technology'. You can override using the `.groups` argument.
datatable(waterWithdrawalsByStateSectorBasin_source, filter = "top")
# create 3 way shares among runoff gw and desal by using  desal from waterWithdrawalsByStateSectorBasin and runoff and gw from waterWithdrawalsByWaterSource
gwRunoffDesalShares <- waterWithdrawalsByWaterSource %>% 
  filter_basin_resource() %>%
  remove_water_withdrawals_string() %>% select(!c("Units", "region")) %>% 
  rbind(waterWithdrawalsByStateSectorBasin %>% 
          filter(region != "USA") %>% 
          filter(technology == "desalination") %>% 
          group_by(scenario, subsector, technology, year) %>%
          summarise(value = sum(value)) %>% ungroup() %>%
          select(scenario, subresource = technology, resource = subsector, year, value)
  ) %>% group_by(scenario, resource, year) %>% mutate(share = value / sum(value)) %>% ungroup()
`summarise()` has grouped output by 'scenario', 'subsector', 'technology'. You can override using the `.groups` argument.
waterWithdrawalsByStateSectorBasin_source_3 <- waterWithdrawalsByStateSectorBasin %>% 
  # filter(scenario == "rcp85cooler_ssp5", year == "2050", sector == "water_td_an_W") %>%
  filter(region != "USA") %>% # exclude USA level data because it aggregated up from basin level data, but lacks the technology detail (name of the basin here)
  filter_CONUSregions(technology, basins_conus_resource) %>% # not sure why nonCONUS basins have crept in here at the technology level, but remove them 
  filter(technology != "desalination") %>% # we have desalination at the basin level in the previous plot 
  replace_after_irr_string() %>% # if this is removed, each basin will supply to it's own irrigation demand
  group_by(scenario, sector, technology, year) %>%
  summarise(value = sum(value)) %>% ungroup() %>%
  select(scenario, source = technology, target = sector, year, demand_withdraw = value) %>% 
  left_join(gwRunoffDesalShares, by = c("scenario", "source" = "resource", "year")) %>% 
  mutate(source_disagg = demand_withdraw * share) 
`summarise()` has grouped output by 'scenario', 'sector', 'technology'. You can override using the `.groups` argument.
waterSourceUseCategories3 <- waterWithdrawalsByStateSectorBasin_source_3 %>% 
  group_by(scenario, subresource, target, year) %>% 
  summarise(value = sum(source_disagg)) %>% ungroup() %>% 
  select(scenario, source = subresource, target, year, value) %>% 
  # note we are aggregating up basin-level irrigation from desalination here 
  rbind(desal_totalUSA %>% replace_after_irr_string(target) %>% 
          group_by(scenario, source, target, year) %>% summarise(value = sum(value)) %>% ungroup()
        ) 
`summarise()` has grouped output by 'scenario', 'subresource', 'target'. You can override using the `.groups` argument.`summarise()` has grouped output by 'scenario', 'source', 'target'. You can override using the `.groups` argument.
plot_sankey(waterSourceUseCategories3, "Water Source and Use Category")  
plot_sankey(rbind(waterSourceUseCategories3, waterCateogryTech), "Water Source, Use Category, and End-Use")

# CONLCUSION: THIS IS EXACTLY THE SAME AS THE ONE PREPARE WIHTOUT 3 WAY SHARES                              
# US level supply and demand
waterSourceUseCategories <- waterWithdrawalsByStateSectorBasin_source %>% 
  group_by(scenario, subresource, target, year) %>% 
  summarise(value = sum(source_disagg)) %>% ungroup() %>% 
  select(scenario, source = subresource, target, year, value) %>% 
  # note we are aggregating up basin-level irrigation from desalination here 
  rbind(desal_totalUSA %>% replace_after_irr_string(target) %>% 
          group_by(scenario, source, target, year) %>% summarise(value = sum(value)) %>% ungroup()
        ) 
`summarise()` has grouped output by 'scenario', 'subresource', 'target'. You can override using the `.groups` argument.`summarise()` has grouped output by 'scenario', 'source', 'target'. You can override using the `.groups` argument.
plot_sankey(waterSourceUseCategories, "Water Source and Use Category")   
NA
# water source, use category, and end-use 
waterCateogryTech <- 
  # we will use different details for each use category 
  rbind(
    # electricity on tech level
    waterWithdrawalsByTech_watCat %>% 
      filter(watcategory == "water_td_elec_W") %>% 
      clean_cooling_tech("technology", cooling_techs, cooling_techs_years) %>%
      group_by(scenario, watcategory, technology, year) %>%
      summarise(value = sum(value)) %>% ungroup() %>% 
      select(scenario, source = watcategory, target = technology, year, value)
    , 
    # everything else on sector level 
    waterWithdrawalsByTech_watCat %>% 
      filter(watcategory != "water_td_elec_W") %>% 
      group_by(scenario, watcategory, sector, year) %>%
      summarise(value = sum(value)) %>% ungroup() %>%
      select(scenario, source = watcategory, target = sector, year, value)
  )
`summarise()` has grouped output by 'scenario', 'watcategory', 'technology'. You can override using the `.groups` argument.`summarise()` has grouped output by 'scenario', 'watcategory', 'sector'. You can override using the `.groups` argument.
plot_sankey(rbind(waterSourceUseCategories, waterCateogryTech), "Water Source, Use Category, and End-Use")
# water source, basin, use category, and end-use
plot_sankey(rbind(df_waterWithdrawalsByWaterSource, df_waterWithdrawalsByStateSectorBasin, waterCateogryTech, hydro_water_req), "Water Source, Basin, Use Category, and End-Use")
# SWAPPED basins: water source, basin, use category, and end-use
water_source_target <- rbind(df_waterWithdrawalsByWaterSource %>% swap_source_target(), 
                  waterSourceUseCategories,
                  waterCateogryTech, hydro_water_req) %>% 
  complete(scenario, year, nesting(source, target), fill = list(value = 0)) %>% mutate(units = "km3") %>% 
  select(scenario, source, target, year, value, units)

plot_sankey(water_source_target, "Water Source, Basin, Use Category, and End-Use")

write_csv(water_source_target , paste0("../", data_dir, "water_source_target.csv"))
# water source, basin, use category, and end-use WITH BETTER COLORS 

waterSourceBasinsCategoriesUse_colors <- read_csv(paste0("../", data_dir, "waterSourceBasinsCategoriesUse.csv"))
Rows: 16861 Columns: 8-- Column specification ---------------------------------------------------------------------------------------------------------
Delimiter: ","
chr (6): scenario, target, source, target_color, source_color, flow_color
dbl (2): year, value
i Use `spec()` to retrieve the full column specification for this data.
i Specify the column types or set `show_col_types = FALSE` to quiet this message.
plot_sankey(waterSourceBasinsCategoriesUse_colors, "Water Source, Basin, Use Category, and End-Use")
# Combine source and target to get unique nodes and their colors
nodes <- waterSourceBasinsCategoriesUse_colors %>%
  select(source, source_color) %>%
  rename(node = source, node_color = source_color) %>%
  bind_rows(
    waterSourceBasinsCategoriesUse_colors %>%
      select(target, target_color) %>%
      rename(node = target, node_color = target_color)
  ) %>%
  distinct()

# Add color directly to node labels
node_labels <- unique(c(waterSourceBasinsCategoriesUse_colors$source, 
                        waterSourceBasinsCategoriesUse_colors$target))

# Map node colors to node labels
node_colors <- nodes$node_color[match(node_labels, nodes$node)]
unique(waterSourceBasinsCategoriesUse_colors[c("source", "source_color")])$source_color[match(node_labels, unique(waterSourceBasinsCategoriesUse_colors$source))]
 [1] "#005F73" "#00B1D1" "#005F73" "#00B1D1" "#005F73" "#00B1D1" "#005F73" "#00B1D1" "#005F73" "#00B1D1" "#005F73" "#00B1D1"
[13] "#005F73" "#00B1D1" "#005F73" "#00B1D1" "#005F73" "#00B1D1" "#005F73" "#00B1D1" "#005F73" "#00B1D1" "#005F73" "#00B1D1"
[25] "#005F73" "#00B1D1" "#005F73" NA        NA        NA        NA        NA        NA        NA        NA        NA       
[37] NA        NA        NA        NA        NA        NA        NA        NA        NA        NA        NA        NA       
[49] NA        NA        NA        NA        NA        NA        NA        NA        NA        NA        NA        NA       
[61] NA        NA        NA        NA        NA        NA        NA        NA        NA        NA        NA        NA       
[73] NA       

Energy Sankey

Overall information required:

Queries:

# read queries 
# GCAM-USA specific queries 
elecEnergyInputByElecGenTechCoolingTech_gUSA <- getQuery(im3_epri, "elec energy input by elec gen tech and cooling tech") %>% filter_CONUSregions()
elecWaterWithdrawByElecGenTechCoolingTech_gUSA <- getQuery(im3_epri, "elec water withdrawals by gen tech and cooling tech") %>% filter_CONUSregions()
elecGenByGenTechCoolingTech_gUSA <- getQuery(im3_epri, "elec gen by gen tech and cooling tech (incl cogen)") %>% filter_CONUSregions()
# generic GCAM queries
elecEnergyInputByElecGenTech <- getQuery(im3_epri, "elec energy input by elec gen tech") %>% filter_CONUSregions()
elecGenByGenTechCoolingTech <- getQuery(im3_epri, "elec gen by gen tech and cooling tech") %>% filter_CONUSregions()
elecWaterWithdrawByGenTech <- getQuery(im3_epri, "elec water withdrawals by gen tech") %>% filter_CONUSregions()
elecTDInputsOutputs <- getQuery(im3_epri, "elec td inputs and outputs") %>% filter_CONUSregions()
elecConsumptionByDemandSector <- getQuery(im3_epri, "elec consumption by demand sector") %>% filter_CONUSregions()
data_tables_ew <- list(
  "elecEnergyInputByElecGenTechCoolingTech_gUSA" = elecEnergyInputByElecGenTechCoolingTech_gUSA,
  "elecWaterWithdrawByElecGenTechCoolingTech_gUSA" = elecWaterWithdrawByElecGenTechCoolingTech_gUSA,
  "elecGenByGenTechCoolingTech_gUSA" = elecGenByGenTechCoolingTech_gUSA,
  "elecEnergyInputByElecGenTech" = elecEnergyInputByElecGenTech,
  "elecGenByGenTechCoolingTech" = elecGenByGenTechCoolingTech,
  "elecWaterWithdrawByGenTech" = elecWaterWithdrawByGenTech,
  "elecTDInputsOutputs" = elecTDInputsOutputs,
  "elecConsumptionByDemandSector" = elecConsumptionByDemandSector
)

# print column names of each datatable
lapply(data_tables_ew, function(x) colnames(x))
$elecEnergyInputByElecGenTechCoolingTech_gUSA
[1] "Units"      "scenario"   "region"     "sector"     "subsector"  "technology" "input"      "year"       "value"     

$elecWaterWithdrawByElecGenTechCoolingTech_gUSA
[1] "Units"      "scenario"   "region"     "sector"     "subsector"  "technology" "input"      "year"       "value"     

$elecGenByGenTechCoolingTech_gUSA
[1] "Units"      "scenario"   "region"     "sector"     "subsector"  "technology" "year"       "value"     

$elecEnergyInputByElecGenTech
[1] "Units"      "scenario"   "region"     "sector"     "subsector"  "technology" "input"      "year"       "value"     

$elecGenByGenTechCoolingTech
[1] "Units"      "scenario"   "region"     "sector"     "subsector"  "technology" "output"     "year"       "value"     

$elecWaterWithdrawByGenTech
[1] "Units"      "scenario"   "region"     "sector"     "subsector"  "technology" "input"      "year"       "value"     

$elecTDInputsOutputs
[1] "Units"    "scenario" "region"   "sector"   "year"     "value"   

$elecConsumptionByDemandSector
[1] "Units"    "scenario" "region"   "sector"   "input"    "year"     "value"   
# print the first few rows of each datatable
lapply(data_tables_ew, function(x) (x))
$elecEnergyInputByElecGenTechCoolingTech_gUSA

$elecWaterWithdrawByElecGenTechCoolingTech_gUSA

$elecGenByGenTechCoolingTech_gUSA

$elecEnergyInputByElecGenTech

$elecGenByGenTechCoolingTech

$elecWaterWithdrawByGenTech

$elecTDInputsOutputs

$elecConsumptionByDemandSector
NA
elec_source_target <- rbind(
  # water withdrawals by electricity generation technology
  elecWaterWithdrawByGenTech %>% 
    # mutate(value = value * 1e-1) %>% # change to x10 km3 for better visuals
    clean_cooling_tech("technology", cooling_techs, cooling_techs_years) %>%
    group_by(scenario, technology, input, year) %>%
    summarise(value = sum(value)) %>% ungroup() %>% 
    select(scenario, source = input , target = technology, year, value)
  ,
  elecEnergyInputByElecGenTech %>% 
    clean_cooling_tech("technology", cooling_techs, cooling_techs_years) %>%
    group_by(scenario, technology, input, year) %>%
    summarise(value = sum(value)) %>% ungroup() %>% 
    select(scenario, source = input , target = technology, year, value)
  ,
  # electricity generation by technology
  elecGenByGenTechCoolingTech %>% 
    clean_cooling_tech("technology", cooling_techs, cooling_techs_years) %>%
    group_by(scenario, subsector, technology, year) %>%
    summarise(value = sum(value)) %>% ungroup() %>% 
    select(scenario, source = technology, target = subsector, year, value)
  ,
  # bridge gen sector to electricity supply sector
  elecGenByGenTechCoolingTech %>%
    # sum by subsector
    group_by(scenario, subsector, output, year) %>%
    summarise(value = sum(value)) %>% ungroup() %>%
    rename(source = subsector, target = output) 
  ,
  # inputs to the end use sectors
  elecTDInputsOutputs %>%
    filter(grepl("elect_", sector)) %>%
    group_by(scenario, sector, year) %>%
    summarise(value = sum(value)) %>% ungroup() %>%
    # TODO: add electricity_net_ownuse, and create a losses "end-use"
    mutate(source = "electricity") %>%
    select(scenario, source, target = sector, year, value)
  ,
  # electricity consumption by demand sector
  elecConsumptionByDemandSector %>%
    group_by(scenario, sector, input, year) %>%
    summarise(value = sum(value)) %>% ungroup() %>%
    select(scenario, source = input, target = sector, year, value)
) %>% filter(source != target)
`summarise()` has grouped output by 'scenario', 'technology', 'input'. You can override using the `.groups` argument.`summarise()` has grouped output by 'scenario', 'technology', 'input'. You can override using the `.groups` argument.`summarise()` has grouped output by 'scenario', 'subsector', 'technology'. You can override using the `.groups` argument.`summarise()` has grouped output by 'scenario', 'subsector', 'output'. You can override using the `.groups` argument.`summarise()` has grouped output by 'scenario', 'sector'. You can override using the `.groups` argument.`summarise()` has grouped output by 'scenario', 'sector', 'input'. You can override using the `.groups` argument.
plot_sankey(elec_source_target, "Electricity Generation and Consumption")
# remove water from electricity diagram 
plot_sankey(elec_source_target %>% filter(source != "water_td_elec_W"), yr = 2050, "Electricity Generation and Consumption")
LS0tDQp0aXRsZTogIkVuZXJneS1XYXRlciBGbG93cyBmcm9tIHRoZSBJTTMgR0NBTS1VU0EgU2NlbmFyaW9zIg0KYXV0aG9yOiAiSGFzc2FuIE5pYXppIChoYXNzYW4ubmlhemlAcG5ubC5nb3YpIg0KZGF0ZTogIkxhc3QgY29tcGlsZWQgb24gYHIgZm9ybWF0KFN5cy50aW1lKCksICclZCAlQiwgJVknKWAiDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6DQogICAgdG9jOiB0cnVlDQogICAgIyB0b2NfZmxvYXQ6IFRSVUUNCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IHRydWUNCiAgICBkZl9wcmludDogcGFnZWQNCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgYnkgZGVmYXVsdCBjb2xsYXBzZS9oaWRlIHRoZSBjb2RlDQojIGtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gRkFMU0UpDQojIHNldCB3b3JraW5nIGRpcmVjdG9yeSB0byBvbmUgZm9sZGVyIHVwDQpzZXR3ZCgiLi4vIikNCiMgZ2V0d2QoKQ0Kc291cmNlKCIuL1IvZnVuY3Rpb25zLlIiKQ0KYGBgDQoNCiMjIEZvciB0aGUgRVBSSSdzIFdFVCBGb3J1bQ0KDQotICAgR29hbDogcGxvdCBhIHdhdGVyIHNhbmtleSwgZW5lcmd5IHNhbmtleSwgZW5lcmd5LXdhdGVyIHNhbmtleSAoZXZlbiBpZiBhIHBhcnRpYWwgb25lKSwgc2hvdyBldm9sdXRpb24gb3ZlciB0aW1lDQotICAgTGV0J3MgaGFuZC1waWNrIHRoZSByZWxldmFudCBxdWVyaWVzLiBPbmNlIGZpbmFsaXplZCwgd2UgY2FuIHVzZSBgcmdjYW1gIHRvIHF1ZXJ5IHRoZSBkYXRhLg0KDQojIyMgUXVlcnkgYW5kIGxvYWQgSU0zIGRhdGENCg0KUnVuIHRoaXMgYHF1ZXJ5X2ltM19zY2VuKCJlcHJpIilgIG9ubHkgb25jZSB0byBxdWVyeSBmcm9tIHJlbW90ZSBJTTMgZGF0YWJhc2VzLiBPbmNlIGEgYC5kYXRgIGZpbGUgaXMgY3JlYXRlZCwgd2UgY2FuIGxvYWQgdGhlIGV4aXN0aW5nIHByb2plY3QgZGF0YSBieSBgbG9hZFByb2plY3QocHJvaiA9ICJpbTNzY2VuX2VwcmkuZGF0IilgLg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBxdWVyeSB0aGUgZGF0YQ0KIyBpbTNfZXByaSA8LSBxdWVyeV9pbTNfc2NlbigiZXByaSIpDQpgYGANCg0KYGBge3IsIHdhcm5pbmcgPSBGQUxTRX0NCiMgbG9hZCB0aGUgZGF0YQ0KaW0zX2VwcmkgPC0gbG9hZFByb2plY3QocHJvaiA9IHBhc3RlMCgiLi4vIiwgZGF0YV9kaXIsICJpbTNzY2VuX2VwcmkuZGF0IikpDQpgYGANCg0KYGBge3J9DQojIHNjZW5hcmlvcyBhbmQgcXVlcmllcyANCmxpc3RTY2VuYXJpb3MoaW0zX2VwcmkpDQpsaXN0UXVlcmllcyhpbTNfZXByaSkNCmBgYA0KDQojIyMgV2F0ZXIgU2Fua2V5DQoNCk92ZXJhbGwgcmVxdWlyZWQgaW5mb3JtYXRpb24NCg0KLSAgIHdhdGVyIGF2YWlsYWJpbGl0eSBieSBzb3VyY2UgKGUuZy4sIGdyb3VuZHdhdGVyLCBzdXJmYWNlIHdhdGVyLCBkZXNhbGluYXRpb24pDQotICAgd2F0ZXIgdXNlIGJ5IGNhdGVnb3JpZXMgKGUuZy4sIGFncmljdWx0dXJlLCBpbmR1c3RyeSwgZG9tZXN0aWMsIHBvd2VyIGV0YykNCi0gICB3YXRlciB1c2UgYnkgZW5kLXVzZSBzZWN0b3JzIChlLmcuLCBjcm9wcywgaW5kdXN0cnksIGVsZWN0cmljaXR5IGV0YykNCg0KR0NBTSBxdWVyaWVzDQoNCi0gICBhdmFpbGFiaWxpdHkNCiAgICAtICAgcmVzb3VyY2Ugc3VwcGx5IGN1cnZlcw0KICAgIC0gICBiYXNpbiBsZXZlbCBhdmFpbGFibGUgcnVub2ZmDQogICAgLSAgIHRvdGFsIHJ1bm9mZiBhdmFpbGFibGUNCiAgICAtICAgdG90YWwgZ3JvdW5kd2F0ZXIgYXZhaWxhYmxlDQotICAgdXNlIGJ5IHNvdXJjZQ0KICAgIC0gICByZXNvdXJjZSBwcm9kdWN0aW9uDQogICAgLSAgIHJlc291cmNlIHByb2R1Y3Rpb24gYnkgdGVjaCBhbmQgdmludGFnZQ0KICAgIC0gICB3YXRlciB3aXRoZHJhd2FscyBieSB3YXRlciBzb3VyY2UgKHJ1bm9mZiB2cy4gZ3JvdW5kd2F0ZXIpDQotICAgdXNlIGJ5IHJlZ2lvbi9iYXNpbg0KICAgIC0gICB3YXRlciB3aXRoZHJhd2FscyBieSByZWdpb24NCi0gICB1c2UgYnkgY2F0ZWdvcnkNCiAgICAtICAgd2F0ZXIgd2l0aGRyYXdhbHMgYnkgd2F0ZXIgbWFwcGluZyBzb3VyY2UNCiAgICAtICAgd2F0ZXIgd2l0aGRyYXdhbHMgYnkgdGVjaA0KICAgIC0gICB3YXRlciB3aXRoZHJhd2FscyBieSB0ZWNoIChhbGwgZWxlYykNCiAgICAtICAgd2F0ZXIgd2l0aGRyYXdhbHMgYnkgc3RhdGUsIHNlY3RvciwgYmFzaW4gKGluY2x1ZGVzIGRlc2FsKQ0KDQpgYGB7ciwgd2FybmluZyA9IEZBTFNFfQ0KIyBnZXQgcXVlcmllcyANCiMgYXZhaWxhYmlsaXR5IA0KcmVzb3VyY2VTdXBwbHlDdXJ2ZXMgPC0gZ2V0UXVlcnkoaW0zX2VwcmksICJyZXNvdXJjZSBzdXBwbHkgY3VydmVzIikgJT4lIGZpbHRlcl9DT05VU3JlZ2lvbnMoKQ0KYmFzaW5MZXZlbEF2YWlsYWJsZVJ1bm9mZiA8LSBnZXRRdWVyeShpbTNfZXByaSwgImJhc2luIGxldmVsIGF2YWlsYWJsZSBydW5vZmYiKSAlPiUgZmlsdGVyX0NPTlVTcmVnaW9ucygpIA0KIyB0b3RhbFJ1bm9mZkF2YWlsYWJsZSA8LSBnZXRRdWVyeShpbTNfZXByaSwgInRvdGFsIHJ1bm9mZiBhdmFpbGFibGUiKSAlPiUgZmlsdGVyX0NPTlVTcmVnaW9ucygpDQp0b3RhbEdyb3VuZHdhdGVyQXZhaWxhYmxlIDwtIGdldFF1ZXJ5KGltM19lcHJpLCAidG90YWwgZ3JvdW5kd2F0ZXIgYXZhaWxhYmxlIikgJT4lIGZpbHRlcl9DT05VU3JlZ2lvbnMoKQ0KIyBwcm9kdWN0aW9uIA0KcmVzb3VyY2VQcm9kdWN0aW9uIDwtIGdldFF1ZXJ5KGltM19lcHJpLCAicmVzb3VyY2UgcHJvZHVjdGlvbiIpICU+JSBmaWx0ZXJfQ09OVVNyZWdpb25zKCkNCnJlc291cmNlUHJvZHVjdGlvbkJ5VGVjaFZpbnRhZ2UgPC0gZ2V0UXVlcnkoaW0zX2VwcmksICJyZXNvdXJjZSBwcm9kdWN0aW9uIGJ5IHRlY2ggYW5kIHZpbnRhZ2UiKSAlPiUgZmlsdGVyX0NPTlVTcmVnaW9ucygpDQp3YXRlcldpdGhkcmF3YWxzQnlXYXRlclNvdXJjZSA8LSBnZXRRdWVyeShpbTNfZXByaSwgIndhdGVyIHdpdGhkcmF3YWxzIGJ5IHdhdGVyIHNvdXJjZSAocnVub2ZmIHZzLiBncm91bmR3YXRlcikiKSAlPiUgZmlsdGVyX0NPTlVTcmVnaW9ucygpDQojIHVzZSBieSByZWdpb24vYmFzaW4gDQojIHdhdGVyV2l0aGRyYXdhbHNCeVJlZ2lvbiA8LSBnZXRRdWVyeShpbTNfZXByaSwgIndhdGVyIHdpdGhkcmF3YWxzIGJ5IHJlZ2lvbiIpICU+JSBmaWx0ZXJfQ09OVVNyZWdpb25zKCkNCndhdGVyV2l0aGRyYXdhbHNCeVN0YXRlU2VjdG9yQmFzaW4gPC0gZ2V0UXVlcnkoaW0zX2VwcmksICJ3YXRlciB3aXRoZHJhd2FscyBieSBzdGF0ZSwgc2VjdG9yLCBiYXNpbiAoaW5jbHVkZXMgZGVzYWwpIikgJT4lIGZpbHRlcl9DT05VU3JlZ2lvbnMoKQ0KIyB1c2UgYnkgY2F0ZWdvcnkgDQp3YXRlcldpdGhkcmF3YWxzQnlXYXRlck1hcHBpbmdTb3VyY2UgPC0gZ2V0UXVlcnkoaW0zX2VwcmksICJ3YXRlciB3aXRoZHJhd2FscyBieSB3YXRlciBtYXBwaW5nIHNvdXJjZSIpICU+JSBmaWx0ZXJfQ09OVVNyZWdpb25zKCkNCndhdGVyV2l0aGRyYXdhbHNCeVRlY2ggPC0gZ2V0UXVlcnkoaW0zX2VwcmksICJ3YXRlciB3aXRoZHJhd2FscyBieSB0ZWNoIikgJT4lIGZpbHRlcl9DT05VU3JlZ2lvbnMoKQ0KIyB3YXRlcldpdGhkcmF3YWxzQnlUZWNoQWxsRWxlYyA8LSBnZXRRdWVyeShpbTNfZXByaSwgIndhdGVyIHdpdGhkcmF3YWxzIGJ5IHRlY2ggKGFsbCBlbGVjKSIpICU+JSBmaWx0ZXJfQ09OVVNyZWdpb25zKCkNCmBgYA0KDQpgYGB7ciwgbWVzc3NhZ2UgPSBULCB3YXJuaW5nID0gRkFMU0V9DQpkYXRhX3RhYmxlc193YXRlciA8LSBsaXN0KA0KICAicmVzb3VyY2VTdXBwbHlDdXJ2ZXMiID0gcmVzb3VyY2VTdXBwbHlDdXJ2ZXMsDQogICJiYXNpbkxldmVsQXZhaWxhYmxlUnVub2ZmIiA9IGJhc2luTGV2ZWxBdmFpbGFibGVSdW5vZmYsDQogICMgInRvdGFsUnVub2ZmQXZhaWxhYmxlIiA9IHRvdGFsUnVub2ZmQXZhaWxhYmxlLA0KICAidG90YWxHcm91bmR3YXRlckF2YWlsYWJsZSIgPSB0b3RhbEdyb3VuZHdhdGVyQXZhaWxhYmxlLA0KICAicmVzb3VyY2VQcm9kdWN0aW9uIiA9IHJlc291cmNlUHJvZHVjdGlvbiwNCiAgInJlc291cmNlUHJvZHVjdGlvbkJ5VGVjaFZpbnRhZ2UiID0gcmVzb3VyY2VQcm9kdWN0aW9uQnlUZWNoVmludGFnZSwNCiAgIndhdGVyV2l0aGRyYXdhbHNCeVdhdGVyU291cmNlIiA9IHdhdGVyV2l0aGRyYXdhbHNCeVdhdGVyU291cmNlLA0KICAjICJ3YXRlcldpdGhkcmF3YWxzQnlSZWdpb24iID0gd2F0ZXJXaXRoZHJhd2Fsc0J5UmVnaW9uLA0KICAid2F0ZXJXaXRoZHJhd2Fsc0J5U3RhdGVTZWN0b3JCYXNpbiIgPSB3YXRlcldpdGhkcmF3YWxzQnlTdGF0ZVNlY3RvckJhc2luLA0KICAid2F0ZXJXaXRoZHJhd2Fsc0J5V2F0ZXJNYXBwaW5nU291cmNlIiA9IHdhdGVyV2l0aGRyYXdhbHNCeVdhdGVyTWFwcGluZ1NvdXJjZSwNCiAgIndhdGVyV2l0aGRyYXdhbHNCeVRlY2giID0gd2F0ZXJXaXRoZHJhd2Fsc0J5VGVjaA0KICAjICJ3YXRlcldpdGhkcmF3YWxzQnlUZWNoQWxsRWxlYyIgPSB3YXRlcldpdGhkcmF3YWxzQnlUZWNoQWxsRWxlYw0KKQ0KDQojIHByaW50IGNvbHVtbiBuYW1lcyBvZiBlYWNoIGRhdGF0YWJsZQ0KbGFwcGx5KGRhdGFfdGFibGVzX3dhdGVyLCBmdW5jdGlvbih4KSBjb2xuYW1lcyh4KSkNCg0KIyBwcmludCB0aGUgZmlyc3QgZmV3IHJvd3Mgb2YgZWFjaCBkYXRhdGFibGUNCmxhcHBseShkYXRhX3RhYmxlc193YXRlciwgZnVuY3Rpb24oeCkgKHgpKQ0KYGBgDQoNCkxldCdzIHByb2Nlc3MgZWFjaCBwaWVjZSB0byBwcmVwYXJlIHRoZSBmb3JtYXQgb2Y6IHNjZW5hcmlvLCBzb3VyY2UsIHRhcmdldCwgeWVhciwgdmFsdWUuIFNjZW5hcmlvIGFuZCB5ZWFyIGNvdWxkIGJlIGZpbHRlcmVkIGZvciBlYWNoIFNhbmtleS4NCg0KIyMjIyBXYXRlciBBdmFpbGFiaWxpdHkNCg0KYGBge3IgZmlnLndpZHRoPTgsIHdhcm5pbmc9RkFMU0V9DQp1bmlxdWUocmVzb3VyY2VTdXBwbHlDdXJ2ZXMkcmVzb3VyY2UpDQp1bmlxdWUocmVzb3VyY2VTdXBwbHlDdXJ2ZXMkc3VicmVzb3VyY2UpDQoNCnJlc291cmNlU3VwcGx5Q3VydmVzX3dhdGVyIDwtIHJlc291cmNlU3VwcGx5Q3VydmVzICU+JSBmaWx0ZXIoc3VicmVzb3VyY2UgJWluJSBjKCJncm91bmR3YXRlciIsICJydW5vZmYiKSkgJT4lIA0KICBmaWx0ZXIoZ3JhZGUgIT0gImdyYWRlIGhpc3QiKSAlPiUgI2V4Y2x1ZGUgaGlzdG9yaWNhbCB1c2FnZQ0KICBmaWx0ZXJfYmFzaW5fcmVzb3VyY2UoKSAlPiUNCiAgZ3JvdXBfYnkoc2NlbmFyaW8sIHJlc291cmNlLCBzdWJyZXNvdXJjZSwgeWVhcikgJT4lIA0KICBzdW1tYXJpc2UodmFsdWUgPSBzdW0odmFsdWUpKSAlPiUgdW5ncm91cCgpICU+JSANCiAgcmVtb3ZlX3dhdGVyX3dpdGhkcmF3YWxzX3N0cmluZygpICU+JSANCiAgc2VsZWN0KHNjZW5hcmlvLCBzb3VyY2UgPSByZXNvdXJjZSwgdGFyZ2V0ID0gc3VicmVzb3VyY2UsIHllYXIsIHZhbHVlKQ0KDQpkYXRhdGFibGUocmVzb3VyY2VTdXBwbHlDdXJ2ZXNfd2F0ZXIsIGZpbHRlciA9ICJ0b3AiKSANCnBsb3Rfc2Fua2V5KHJlc291cmNlU3VwcGx5Q3VydmVzX3dhdGVyLCAiV2F0ZXIgQXZhaWxhYmlsaXR5IGJ5IEJhc2luIGFuZCBSZXNvdXJjZSBUeXBlIikNCg0KYGBgDQoNClRvdGFsIHJlc291cmNlIGF2YWlsYWJpbGl0eSBkb2Vzbid0IGNoYW5nZSBvdmVyIHRpbWUuIFRoaXMgZG9lc24ndCBsb29rIHJpZ2h0IGJlY2F1c2UgYmFzaW4gbGV2ZWwgYXZhaWxhYmxlIHJ1bm9mZiAod2hpY2ggdXNlcyBgbWF4LWFubnVhbC1zdWJyZXNvdXJjZWAgaW5zdGVhZCBvZiBzdW1taW5nIGFsbCBgZ3JhZGVzYCkgaXMgbXVjaCBtb3JlIGFuZCBjaGFuZ2VzIG92ZXIgdGltZS4NCg0KPCEtLSAtICAgKnRvdGFsUnVub2ZmQXZhaWxhYmxlKiBhbmQgYHRvdGFsR3JvdW5kd2F0ZXJBdmFpbGFibGVgIGFyZSB0aGUgcHJlLWZpbHRlcmVkIHZlcnNpb25zIG9mIGByZXNvdXJjZVN1cHBseUN1cnZlc2AgKGkuZS4sIHRoZXkgZmlsdGVyIGZvciBzdWJyZXNvdXJjZSBqdXN0IGxpa2Ugd2UgZGlkIGFib3ZlKSAtLT4NCjwhLS0gLSAgICp0b3RhbFJ1bm9mZkF2YWlsYWJsZSogYW5kIGB0b3RhbEdyb3VuZHdhdGVyQXZhaWxhYmxlYCBhcmUgdGhlIHNhbWUgYXMgYHJlc291cmNlU3VwcGx5Q3VydmVzYCBidXQgdGhleSBhcmUgZmlsdGVyZWQgZm9yIHRoZSBVU0EgcmVnaW9uLiAtLT4NCjwhLS0gLSAgIElNUE9SVEFOVDogKnRvdGFsUnVub2ZmQXZhaWxhYmxlKiBzaG91bGQgTk9UIGJlIHVzZWQgYmVjYXVzZSBydW5vZmYgYXZhaWxhYmlsaXR5IGlzIHNwZWNpZmllZCBieSB0aGUgYG1heC1hbm51YWwtc3VicmVzb3VyY2VgLCBub3QgdGhlIGBncmFkZWAgLS0+DQoNCg0KYGBgeG1sDQo8cmVzb3VyY2VRdWVyeSB0aXRsZT0idG90YWwgZ3JvdW5kd2F0ZXIgYXZhaWxhYmxlIj4NCiAgICA8YXhpczEgbmFtZT0iZ3JhZGUiPmdyYWRlPC9heGlzMT4NCiAgICA8YXhpczIgbmFtZT0iWWVhciI+YXZhaWxhYmxlPC9heGlzMj4NCiAgICA8eFBhdGggYnVpbGRMaXN0PSJ0cnVlIiBkYXRhTmFtZT0ib3V0cHV0IiBncm91cD0iZmFsc2UiIHN1bUFsbD0idHJ1ZSI+KltAdHlwZT0ncmVzb3VyY2UnXS8qW0B0eXBlPSdzdWJyZXNvdXJjZScgYW5kIEBuYW1lPSdncm91bmR3YXRlciddL2dyYWRlL2F2YWlsYWJsZS9ub2RlKCk8L3hQYXRoPg0KPC9yZXNvdXJjZVF1ZXJ5Pg0KYGBgDQoNCg0KYGJhc2luTGV2ZWxBdmFpbGFibGVSdW5vZmZgIGlzIHRoZSBvbmUgdGhhdCB1c2VzIGBtYXgtYW5udWFsLXN1YnJlc291cmNlYCBpbnN0ZWFkIG9mIHN1bW1pbmcgYWxsIGBncmFkZXNgDQoNCmBgYHhtbA0KPHJlc291cmNlUXVlcnkgdGl0bGU9ImJhc2luIGxldmVsIGF2YWlsYWJsZSBydW5vZmYiPg0KICAgIDxheGlzMSBuYW1lPSJCYXNpbiI+cmVzb3VyY2VbQG5hbWVdPC9heGlzMT4NCiAgICA8YXhpczIgbmFtZT0iWWVhciI+bWF4LWFubnVhbC1zdWJyZXNvdXJjZVtAeWVhcl08L2F4aXMyPg0KICAgIDx4UGF0aCBidWlsZExpc3Q9InRydWUiIGRhdGFOYW1lPSJpbnB1dCIgZ3JvdXA9ImZhbHNlIiBzdW1BbGw9ImZhbHNlIj4qW0B0eXBlID0gJ3Jlc291cmNlJyBhbmQgY29udGFpbnMoQG5hbWUsICd3YXRlciB3aXRoZHJhd2FscycpXS8qW0B0eXBlID0gJ3N1YnJlc291cmNlJyBhbmQgY29udGFpbnMoQG5hbWUsICdydW5vZmYnKV0vbWF4LWFubnVhbC1zdWJyZXNvdXJjZS9ub2RlKCk8L3hQYXRoPg0KPC9yZXNvdXJjZVF1ZXJ5Pg0KYGBgDQoNCkxldCdzIHVzZSBhIGNvbWJpbmF0aW9uIG9mIGBiYXNpbkxldmVsQXZhaWxhYmxlUnVub2ZmYCBhbmQgYHRvdGFsR3JvdW5kd2F0ZXJBdmFpbGFibGVgIHRvIGdldCB0aGUgdG90YWwgd2F0ZXIgYXZhaWxhYmlsaXR5IGJ5IGJhc2luIGFuZCB5ZWFyLg0KDQpgYGB7ciBmaWcud2lkdGg9OCwgd2FybmluZz1GQUxTRX0NCnRvdGFsV2F0ZXJBdmFpbGFiaWxpdHkgPC0gcmJpbmQoDQogIGJhc2luTGV2ZWxBdmFpbGFibGVSdW5vZmYgJT4lIGZpbHRlcl9iYXNpbl9yZXNvdXJjZShiYXNpbikgJT4lIHJlbW92ZV93YXRlcl93aXRoZHJhd2Fsc19zdHJpbmcoYmFzaW4pICU+JSANCiAgICAjIHdlIG1heSBoYXZlIHRvIHN3aXRjaCB0aGUgc291cmNlIGFuZCB0YXJnZXQgaGVyZSB0byBzdGFydCBmcm9tIHdhdGVyIHNvdXJjZXMgYW5kIGdvIHRvIGJhc2lucw0KICAgIHNlbGVjdChzY2VuYXJpbywgdGFyZ2V0ID0gYmFzaW4sIHNvdXJjZSA9IHN1YnJlc291cmNlLCB5ZWFyLCB2YWx1ZSksDQogIHRvdGFsR3JvdW5kd2F0ZXJBdmFpbGFibGUgJT4lIA0KICAgIGZpbHRlcl9iYXNpbl9yZXNvdXJjZSgpICU+JSByZW1vdmVfd2F0ZXJfd2l0aGRyYXdhbHNfc3RyaW5nKCkgJT4lIA0KICAgIGZpbHRlcihncmFkZSAhPSAiZ3JhZGUgaGlzdCIpICU+JSANCiAgICBncm91cF9ieShzY2VuYXJpbywgcmVzb3VyY2UsIHN1YnJlc291cmNlLCB5ZWFyKSAlPiUNCiAgICBzdW1tYXJpc2UodmFsdWUgPSBzdW0odmFsdWUpKSAlPiUgdW5ncm91cCgpICU+JQ0KICAgIHNlbGVjdChzY2VuYXJpbywgdGFyZ2V0ID0gcmVzb3VyY2UsIHNvdXJjZSA9IHN1YnJlc291cmNlLCB5ZWFyLCB2YWx1ZSkNCikNCg0KZGF0YXRhYmxlKHRvdGFsV2F0ZXJBdmFpbGFiaWxpdHksIGZpbHRlciA9ICJ0b3AiKQ0KcGxvdF9zYW5rZXkodG90YWxXYXRlckF2YWlsYWJpbGl0eSwgIlRvdGFsIFdhdGVyIEF2YWlsYWJpbGl0eSBieSBCYXNpbiBhbmQgUmVzb3VyY2UgVHlwZSIpDQoNCmBgYA0KDQpUaGlzIGxvb2tzIGJldHRlciEgTGV0J3MgbW92ZSB0byB3YXRlciB3aXRoZHJhd2Fscy4NCg0KIyMjIyBXYXRlciBXaXRoZHJhd2Fscw0KDQpMZXQncyBzdGFydCBieSBxdWFudGlmeWluZyB3YXRlciB3aXRoZHJhd2FscyBieSB3YXRlciBzb3VyY2UgKHJ1bm9mZiB2cy4gZ3JvdW5kd2F0ZXIpIGZvciBlYWNoIGJhc2luLg0KDQotIGByZXNvdXJjZVByb2R1Y3Rpb25gIGdpdmVzIEFMTCByZXNvdXJjZXMsIHdvdWxkIG5lZWQgdG8gZmlsdGVyIGJ5IGBfd2F0ZXIgd2l0aGRyYXdhbHNgLiBCVVQgdGhpcyB3aWxsIGdpdmUgVE9UQUwgYmFzaW4gbGV2ZWwgcHJvZHVjdGlvbiAoYXMgYmFzaW5zIGFyZSAqcmVzb3VyY2VzKikgYW5kIG5vdCBieSB3YXRlciBzb3VyY2UgKHJ1bm9mZiB2cy4gZ3JvdW5kd2F0ZXIpIHdoaWNoIGFyZSAqc3VicmVzb3VyY2VzKi4NCi0gYHJlc291cmNlUHJvZHVjdGlvbkJ5VGVjaFZpbnRhZ2VgIGlzIHRoZSBtb3N0IGRldGFpbGVkIHJlc291cmNlIHF1ZXJ5LCB3aXRoIGluZm9ybWF0aW9uIGZvciByZWdpb25zLCByZXNvdXJjZXMgKHdhdGVyIHdpdGhkcmF3YWxzKSwgc3VicmVzb3VyY2VzIChydW5vZmYsIGdyb3VuZHdhdGVyKSwgcHJvZHVjdGlvbiBieSB5ZWFyLiANCg0KQnV0IGxldCdzIHVzZSBhIHJlYWR5LW1hZGUgcXVlcnkgYHdhdGVyV2l0aGRyYXdhbHNCeVdhdGVyU291cmNlYCB3aGljaCBnaXZlcyB3YXRlciB3aXRoZHJhd2FscyBieSB3YXRlciBzb3VyY2UgKHJ1bm9mZiB2cy4gZ3JvdW5kd2F0ZXIpIGZvciBlYWNoIGJhc2luIChyZXNvdXJjZSkuDQoNCi0gSG93ZXZlciwgdGhpcyBzdGlsbCBkb2Vzbid0IGhhdmUgZGVzYWxpbmF0aW9uLiBgcmVzb3VyY2VQcm9kdWN0aW9uYCBoYXMgZGVzYWxpbmF0aW9uLCBidXQgb24gdGhlIFVTQSBsZXZlbC4gV2Ugd2lsbCBuZWVkIHRvIGdldCBkZXNhbGluYXRpb24gZnJvbSBgd2F0ZXJXaXRoZHJhd2Fsc0J5U3RhdGVTZWN0b3JCYXNpbmAuIA0KDQoNCmBgYHtyIGZpZy53aWR0aD04LCB3YXJuaW5nPUZBTFNFfQ0KIyBwcmVwYXJlIGRlc2FsaW5hdGlvbiB0YWJsZXMgDQpkZXNhbEJ5QmFzaW4gPC0gd2F0ZXJXaXRoZHJhd2Fsc0J5U3RhdGVTZWN0b3JCYXNpbiAlPiUgDQogICAgZmlsdGVyKHJlZ2lvbiAhPSAiVVNBIikgJT4lIA0KICAgIGZpbHRlcih0ZWNobm9sb2d5ID09ICJkZXNhbGluYXRpb24iKSAlPiUNCiAgICBmaWx0ZXJfQ09OVVNyZWdpb25zKHN1YnNlY3RvciwgYmFzaW5zX2NvbnVzX3Jlc291cmNlKSAlPiUgDQogICAgZ3JvdXBfYnkoc2NlbmFyaW8sIHN1YnNlY3RvciwgdGVjaG5vbG9neSwgeWVhcikgJT4lDQogICAgc3VtbWFyaXNlKHZhbHVlID0gc3VtKHZhbHVlKSkgJT4lIHVuZ3JvdXAoKSAlPiUNCiAgICBzZWxlY3Qoc2NlbmFyaW8sIHNvdXJjZSA9IHRlY2hub2xvZ3ksIHRhcmdldCA9IHN1YnNlY3RvciwgeWVhciwgdmFsdWUpDQoNCmRlc2FsQnlVc2VDYXRlZ29yeSA8LSB3YXRlcldpdGhkcmF3YWxzQnlTdGF0ZVNlY3RvckJhc2luICU+JSANCiAgICBmaWx0ZXIocmVnaW9uICE9ICJVU0EiKSAlPiUgDQogICAgZmlsdGVyKHRlY2hub2xvZ3kgPT0gImRlc2FsaW5hdGlvbiIpICU+JSANCiAgICBmaWx0ZXJfQ09OVVNyZWdpb25zKHN1YnNlY3RvciwgYmFzaW5zX2NvbnVzX3Jlc291cmNlKSAlPiUgDQogICAgZ3JvdXBfYnkoc2NlbmFyaW8sIHNlY3RvciwgdGVjaG5vbG9neSwgeWVhcikgJT4lDQogICAgc3VtbWFyaXNlKHZhbHVlID0gc3VtKHZhbHVlKSkgJT4lIHVuZ3JvdXAoKSAlPiUNCiAgICBzZWxlY3Qoc2NlbmFyaW8sIHNvdXJjZSA9IHRlY2hub2xvZ3ksIHRhcmdldCA9IHNlY3RvciwgeWVhciwgdmFsdWUpDQoNCmRlc2FsQnlTdGF0ZSA8LSB3YXRlcldpdGhkcmF3YWxzQnlTdGF0ZVNlY3RvckJhc2luICU+JQ0KICAgIGZpbHRlcihyZWdpb24gIT0gIlVTQSIpICU+JSANCiAgICBmaWx0ZXIodGVjaG5vbG9neSA9PSAiZGVzYWxpbmF0aW9uIikgJT4lIA0KICAgIGZpbHRlcl9DT05VU3JlZ2lvbnMoc3Vic2VjdG9yLCBiYXNpbnNfY29udXNfcmVzb3VyY2UpICU+JSAgIA0KICAgIGdyb3VwX2J5KHNjZW5hcmlvLCByZWdpb24sIHRlY2hub2xvZ3ksIHllYXIpICU+JQ0KICAgIHN1bW1hcmlzZSh2YWx1ZSA9IHN1bSh2YWx1ZSkpICU+JSB1bmdyb3VwKCkgJT4lDQogICAgc2VsZWN0KHNjZW5hcmlvLCBzb3VyY2UgPSB0ZWNobm9sb2d5LCB0YXJnZXQgPSByZWdpb24sIHllYXIsIHZhbHVlKQ0KDQoNCnBsb3Rfc2Fua2V5KHJiaW5kKHRvdGFsV2F0ZXJBdmFpbGFiaWxpdHksIGRlc2FsQnlCYXNpbiksICJUb3RhbCBXYXRlciBBdmFpbGFiaWxpdHkgYnkgQmFzaW4gYW5kIFJlc291cmNlIFR5cGUiKQ0KYGBgDQoNCmBgYHtyIGZpZy53aWR0aD04LCB3YXJuaW5nPUZBTFNFfQ0KZGZfd2F0ZXJXaXRoZHJhd2Fsc0J5V2F0ZXJTb3VyY2UgPC0gcmJpbmQoDQogIHdhdGVyV2l0aGRyYXdhbHNCeVdhdGVyU291cmNlICU+JSANCiAgICBmaWx0ZXJfYmFzaW5fcmVzb3VyY2UoKSAlPiUgDQogICAgcmVtb3ZlX3dhdGVyX3dpdGhkcmF3YWxzX3N0cmluZygpICU+JQ0KICAgIHNlbGVjdChzY2VuYXJpbywgc291cmNlID0gc3VicmVzb3VyY2UsIHRhcmdldCA9IHJlc291cmNlLCB5ZWFyLCB2YWx1ZSkNCiAgLCANCiAgZGVzYWxCeUJhc2luDQogICkNCg0KZGF0YXRhYmxlKGRmX3dhdGVyV2l0aGRyYXdhbHNCeVdhdGVyU291cmNlLCBmaWx0ZXIgPSAidG9wIikNCnBsb3Rfc2Fua2V5KGRmX3dhdGVyV2l0aGRyYXdhbHNCeVdhdGVyU291cmNlLCAiV2F0ZXIgV2l0aGRyYXdhbHMgYnkgQmFzaW4gYW5kIFdhdGVyIFNvdXJjZSIpDQoNCmBgYA0KLSBPbmx5IDcgYmFzaW5zIHVzZSBncm91bmR3YXRlciBpbiAyMDUwIGV4YW1wbGUgYWJvdmUuIA0KDQojIyMjIFdhdGVyIFdpdGhkcmF3YWxzIGJ5IFN0YXRlLCBTZWN0b3IsIGFuZCBCYXNpbg0KYGBge3IgZmlnLndpZHRoPTgsIHdhcm5pbmc9RkFMU0V9DQoNCmRmX3dhdGVyV2l0aGRyYXdhbHNCeVN0YXRlU2VjdG9yQmFzaW4gPC0gd2F0ZXJXaXRoZHJhd2Fsc0J5U3RhdGVTZWN0b3JCYXNpbiAlPiUgDQogIGZpbHRlcihyZWdpb24gIT0gIlVTQSIpICU+JSAjIGV4Y2x1ZGUgVVNBIGxldmVsIGRhdGEgYmVjYXVzZSBpdCBhZ2dyZWdhdGVkIHVwIGZyb20gYmFzaW4gbGV2ZWwgZGF0YSwgYnV0IGxhY2tzIHRoZSB0ZWNobm9sb2d5IGRldGFpbCAobmFtZSBvZiB0aGUgYmFzaW4gaGVyZSkNCiAgZmlsdGVyX0NPTlVTcmVnaW9ucyh0ZWNobm9sb2d5LCBiYXNpbnNfY29udXNfcmVzb3VyY2UpICU+JSAjIG5vdCBzdXJlIHdoeSBub25DT05VUyBiYXNpbnMgaGF2ZSBjcmVwdCBpbiBoZXJlIGF0IHRoZSB0ZWNobm9sb2d5IGxldmVsLCBidXQgcmVtb3ZlIHRoZW0gDQogIGZpbHRlcih0ZWNobm9sb2d5ICE9ICJkZXNhbGluYXRpb24iKSAlPiUgIyB3ZSBoYXZlIGRlc2FsaW5hdGlvbiBhdCB0aGUgYmFzaW4gbGV2ZWwgaW4gdGhlIHByZXZpb3VzIHBsb3QgDQogIHJlcGxhY2VfYWZ0ZXJfaXJyX3N0cmluZygpICU+JSAjIGlmIHRoaXMgaXMgcmVtb3ZlZCwgZWFjaCBiYXNpbiB3aWxsIHN1cHBseSB0byBpdCdzIG93biBpcnJpZ2F0aW9uIGRlbWFuZA0KICBncm91cF9ieShzY2VuYXJpbywgc2VjdG9yLCB0ZWNobm9sb2d5LCB5ZWFyKSAlPiUNCiAgc3VtbWFyaXNlKHZhbHVlID0gc3VtKHZhbHVlKSkgJT4lIHVuZ3JvdXAoKSAlPiUNCiAgc2VsZWN0KHNjZW5hcmlvLCBzb3VyY2UgPSB0ZWNobm9sb2d5LCB0YXJnZXQgPSBzZWN0b3IsIHllYXIsIHZhbHVlKQ0KDQpkYXRhdGFibGUoZGZfd2F0ZXJXaXRoZHJhd2Fsc0J5U3RhdGVTZWN0b3JCYXNpbiwgZmlsdGVyID0gInRvcCIpDQpwbG90X3NhbmtleShkZl93YXRlcldpdGhkcmF3YWxzQnlTdGF0ZVNlY3RvckJhc2luLCAiV2F0ZXIgV2l0aGRyYXdhbHMgYnkgVXNlIENhdGVnb3J5IGFuZCBCYXNpbiIpDQoNCiMgbGV0J3MgdHJ5IHRvIHBpZWNlIHRoaXMgd2l0aCB3YXRlcldpdGhkcmF3YWxzQnlXYXRlclNvdXJjZSB0byB0aGUgdGhlIHdhdGVyIHNvdXJjZSB0eXBlLCBiYXNpbiwgd2F0ZXIgdXNlIHR5cGUgZmxvdw0KcGxvdF9zYW5rZXkocmJpbmQoZGZfd2F0ZXJXaXRoZHJhd2Fsc0J5U3RhdGVTZWN0b3JCYXNpbiwgZGZfd2F0ZXJXaXRoZHJhd2Fsc0J5V2F0ZXJTb3VyY2UpLCAiV2F0ZXIgV2l0aGRyYXdhbHMgYnkgVXNlIENhdGVnb3J5IGFuZCBCYXNpbiIpDQoNCmBgYA0KVE9ETzogUTogV2hhdCBpcyBnb2luZyBvbiB3aXRoIEdyZWF0IExha2VzPyBXaHkgaXMgaXQgc2hvd2luZyB1cCBpbiB0aGUgd2F0ZXIgd2l0aGRyYXdhbHMgYnV0IG5vdCBpbiB0aGUgd2F0ZXIgYXZhaWxhYmlsaXR5PyANCmBgYHtyIGZpZy53aWR0aD04LCB3YXJuaW5nPUZBTFNFfQ0KIyBleGNsdWRlIGdyZWF0IGxha2VzIGZvciBub3cgDQojIHdlIGJyb3VnaHQgaXQgYmFjayBieSBib3Jyb3dpbmcgZnJvbSBDYW5hZGEuIA0KIyBkZl93YXRlcldpdGhkcmF3YWxzQnlTdGF0ZVNlY3RvckJhc2luIDwtIGRmX3dhdGVyV2l0aGRyYXdhbHNCeVN0YXRlU2VjdG9yQmFzaW4gJT4lIGZpbHRlcihzb3VyY2UgIT0gIkdyZWF0IExha2VzIikNCg0KIyBwbG90X3NhbmtleShyYmluZChkZl93YXRlcldpdGhkcmF3YWxzQnlTdGF0ZVNlY3RvckJhc2luLCBkZl93YXRlcldpdGhkcmF3YWxzQnlXYXRlclNvdXJjZSksICJXYXRlciBXaXRoZHJhd2FscyBieSBVc2UgQ2F0ZWdvcnkgYW5kIEJhc2luIikNCmBgYA0KDQoNCiMjIyMgRGV0YWlsZWQgV2F0ZXIgVXNlIA0KTGV0J3MgZGV2ZWxvcCB0aGUgd2F0ZXIgdXNlIGNhdGVnb3JpZXMgZnVydGhlci4NCg0KLSBib3RoIGB3YXRlcldpdGhkcmF3YWxzQnlUZWNoYCBhbmQgYHdhdGVyV2l0aGRyYXdhbHNCeVRlY2hBbGxFbGVjYCBhcmUgdGhlIHNhbWUgcXVlcmllcy4gDQotIGdldCBzaG9ydCBiYXNpbiBuYW1lcyBgdW5pcXVlKCh3YXRlcldpdGhkcmF3YWxzQnlUZWNoX3dhdENhdCAlPiUgZmlsdGVyKGdyZXBsKCJiaW9tYXNzVHJlZSIsIHN1YnNlY3RvcikpKSRzdWJzZWN0b3IpYA0KDQpgYGB7ciBmaWcud2lkdGg9OCwgd2FybmluZz1GQUxTRX0NCndhdGVyV2l0aGRyYXdhbHNCeVRlY2hfd2F0Q2F0IDwtIHdhdGVyV2l0aGRyYXdhbHNCeVRlY2ggJT4lIG1hcF93YXRlcl91c2VfdG9fY2F0ZWdvcmllcygpICU+JSBmaWx0ZXJfQ09OVVNyZWdpb25zKHJlZ2lvbiwgc3RhdGVzX2NvbnVzKQ0KDQp3YXRjYXRlZ29yeV9zZWN0b3JfdXNlIDwtIHdhdGVyV2l0aGRyYXdhbHNCeVRlY2hfd2F0Q2F0ICU+JSANCiAgZ3JvdXBfYnkoc2NlbmFyaW8sIHNlY3Rvciwgd2F0Y2F0ZWdvcnksIHllYXIpICU+JQ0KICBzdW1tYXJpc2UodmFsdWUgPSBzdW0odmFsdWUpKSAlPiUgdW5ncm91cCgpICU+JQ0KICBzZWxlY3Qoc2NlbmFyaW8sIHNvdXJjZSA9IHdhdGNhdGVnb3J5LCB0YXJnZXQgPSBzZWN0b3IsIHllYXIsIHZhbHVlKQ0KDQoNCnBsb3Rfc2Fua2V5KHJiaW5kKGRmX3dhdGVyV2l0aGRyYXdhbHNCeVN0YXRlU2VjdG9yQmFzaW4sIGRmX3dhdGVyV2l0aGRyYXdhbHNCeVdhdGVyU291cmNlLCB3YXRjYXRlZ29yeV9zZWN0b3JfdXNlKSwgIldhdGVyIFdpdGhkcmF3YWxzIGJ5IFVzZSBDYXRlZ29yeSBhbmQgQmFzaW4iKQ0KDQojIHVzZSBieSBzdWJzZWN0b3I6IHNhbWUgcGxvdCBhcyBwcmV2aW91cyBhZnRlciBhZ2dyZWdhdGlvbiANCiMgd2F0Y2F0ZWdvcnlfc3Vic2VjdG9yX3VzZSA8LSB3YXRlcldpdGhkcmF3YWxzQnlUZWNoX3dhdENhdCAlPiUgDQojICAgcmVtb3ZlX0dMVW5hbWVzKHN1YnNlY3RvcikgJT4lIA0KIyAgIGdyb3VwX2J5KHNjZW5hcmlvLCBzdWJzZWN0b3IsIHdhdGNhdGVnb3J5LCB5ZWFyKSAlPiUNCiMgICBzdW1tYXJpc2UodmFsdWUgPSBzdW0odmFsdWUpKSAlPiUgdW5ncm91cCgpICU+JQ0KIyAgIHNlbGVjdChzY2VuYXJpbywgc291cmNlID0gd2F0Y2F0ZWdvcnksIHRhcmdldCA9IHN1YnNlY3RvciwgeWVhciwgdmFsdWUpDQoNCiMgdGhpcyBpcyBlc3NlbnRpYWxseSB0aGUgc2FtZSBhcyB0aGUgcHJldmlvdXMgcGxvdA0KIyBwbG90X3NhbmtleShyYmluZChkZl93YXRlcldpdGhkcmF3YWxzQnlTdGF0ZVNlY3RvckJhc2luLCBkZl93YXRlcldpdGhkcmF3YWxzQnlXYXRlclNvdXJjZSwgd2F0Y2F0ZWdvcnlfc3Vic2VjdG9yX3VzZSksICJXYXRlciBXaXRoZHJhd2FscyBieSBVc2UgQ2F0ZWdvcnkgYW5kIEJhc2luIikNCmBgYA0KDQpgYGB7ciBmaWcud2lkdGg9OCwgd2FybmluZz1GQUxTRX0NCiMgZXhwYW5kIGVsZWN0cmljaXR5IHdhdGVyIHVzZSANCndhdGNhdGVnb3J5X3N1YnNlY3Rvcl91c2UgPC0gd2F0ZXJXaXRoZHJhd2Fsc0J5VGVjaF93YXRDYXQgJT4lIA0KICBmaWx0ZXIoc2VjdG9yID09ICJlbGVjdHJpY2l0eSIpICU+JQ0KICAjIHJlbW92ZV9HTFVuYW1lcyhzdWJzZWN0b3IpICU+JQ0KICBncm91cF9ieShzY2VuYXJpbywgc2VjdG9yLCBzdWJzZWN0b3IsIHllYXIpICU+JQ0KICBzdW1tYXJpc2UodmFsdWUgPSBzdW0odmFsdWUpKSAlPiUgdW5ncm91cCgpICU+JQ0KICBzZWxlY3Qoc2NlbmFyaW8sIHNvdXJjZSA9IHNlY3RvciwgdGFyZ2V0ID0gc3Vic2VjdG9yLCB5ZWFyLCB2YWx1ZSkNCg0KcGxvdF9zYW5rZXkocmJpbmQoZGZfd2F0ZXJXaXRoZHJhd2Fsc0J5U3RhdGVTZWN0b3JCYXNpbiwgZGZfd2F0ZXJXaXRoZHJhd2Fsc0J5V2F0ZXJTb3VyY2UsIHdhdGNhdGVnb3J5X3NlY3Rvcl91c2UsIHdhdGNhdGVnb3J5X3N1YnNlY3Rvcl91c2UpLCAiV2F0ZXIgV2l0aGRyYXdhbHMgYnkgVXNlIENhdGVnb3J5IGFuZCBCYXNpbiIpDQpgYGANCg0KDQpGdXJ0aGVyIHRlY2hub2xvZ3kgbGV2ZWwgZGlzYWdncmVnYXRpb24gZm9yIGVsZWN0cmljaXR5IHdhdGVyIHVzZSANCmBgYHtyIGZpZy53aWR0aD05LCB3YXJuaW5nPUZBTFNFfQ0Kd2F0ZXJFbmR1c2VCeVRlY2ggPC0gd2F0ZXJXaXRoZHJhd2Fsc0J5VGVjaF93YXRDYXQgJT4lIA0KICBmaWx0ZXIoc2VjdG9yID09ICJlbGVjdHJpY2l0eSIpICU+JQ0KICBjbGVhbl9jb29saW5nX3RlY2goInRlY2hub2xvZ3kiLCBjb29saW5nX3RlY2hzLCBjb29saW5nX3RlY2hzX3llYXJzKSAlPiUgDQogIGdyb3VwX2J5KHNjZW5hcmlvLCBzdWJzZWN0b3IsIHRlY2hub2xvZ3ksIHllYXIpICU+JQ0KICBzdW1tYXJpc2UodmFsdWUgPSBzdW0odmFsdWUpKSAlPiUgdW5ncm91cCgpICU+JQ0KICBzZWxlY3Qoc2NlbmFyaW8sIHNvdXJjZSA9IHN1YnNlY3RvciwgdGFyZ2V0ID0gdGVjaG5vbG9neSwgeWVhciwgdmFsdWUpDQoNCnBsb3Rfc2Fua2V5KHJiaW5kKGRmX3dhdGVyV2l0aGRyYXdhbHNCeVN0YXRlU2VjdG9yQmFzaW4sIGRmX3dhdGVyV2l0aGRyYXdhbHNCeVdhdGVyU291cmNlLCB3YXRjYXRlZ29yeV9zZWN0b3JfdXNlLCB3YXRjYXRlZ29yeV9zdWJzZWN0b3JfdXNlLCB3YXRlckVuZHVzZUJ5VGVjaCksICJXYXRlciBVc2UgYnkgU291cmNlLCBCYXNpbiwgQ2F0ZWdvcnksIFNlY3RvciwgYW5kIFRlY2hub2xvZ3ksIGFuZCBCYXNpbiIpDQoNCmBgYA0KDQojIyMjIFdhdGVyIFJlcXVpcmVtZW50IGZvciBIeWRybw0KDQpgYGAge3IgZmlnLndpZHRoPTksIHdhcm5pbmc9RkFMU0V9DQojIGFkZCB3YXRlciByZXF1aXJlbWVudCBmb3IgaHlkcm8gaW4gdGhlIHdhdGVyIGRpYWdyYW0gDQojIGlkZWFsbHkgdXNlIGh5ZHJvIGdlbmVyYXRpb24gYW5kIGNyZWF0ZSBhIHdhdGVyIGZsb3cgZHluYW1pY2FsbHkgZm9yIGFsbCBzY2VuYXJpb3MgYWxsIHllYXJzIHVzaW5nIHRoZSAzMDYwIGttMy9FSiAoODUzIE1HL0JCVFUpIGNvZWZmaWNpZW50IA0KIyBidXQgcmlnaHQgbm93LCBJIGFtIGp1c3QgZ29pbmcgdG8gY3JlYXRlIGEgc2luZ2xlIHZhbHVlDQoNCiMgaHlkcm8gd2F0ZXIgcmVxdWlyZW1lbnQgDQoNCnBsb3Rfc2Fua2V5KHJiaW5kKGRmX3dhdGVyV2l0aGRyYXdhbHNCeVN0YXRlU2VjdG9yQmFzaW4sIGRmX3dhdGVyV2l0aGRyYXdhbHNCeVdhdGVyU291cmNlLCB3YXRjYXRlZ29yeV9zZWN0b3JfdXNlLCANCiAgICAgICAgICAgICAgICAgIHdhdGNhdGVnb3J5X3N1YnNlY3Rvcl91c2UgJT4lIA0KICAgICAgICAgICAgICAgICAgICAjIGFkZCBoeWRybyBmb3IgcmNwNDVjb29sZXJfc3NwMyBzY2VuYXJpbyBhbmQgeWVhciAyMDUwDQogICAgICAgICAgICAgICAgICAgIGFkZF9yb3coc2NlbmFyaW8gPSAicmNwNDVjb29sZXJfc3NwMyIsIHNvdXJjZSA9ICJlbGVjdHJpY2l0eSIsIHRhcmdldCA9ICJoeWRybyIsIHllYXIgPSAyMDUwLCB2YWx1ZSA9IDAuOTk1ICogMzA2MCksDQogICAgICAgICAgICAgICAgICB3YXRlckVuZHVzZUJ5VGVjaCkgJT4lIHJlbmFtZV93YXRlcl91c2VfY2F0ZWdvcmllcygpICU+JSANCiAgICAgICAgICAgICAgbXV0YXRlKHNvdXJjZSA9IGlmZWxzZShzb3VyY2UgPT0gInJ1bm9mZiIsICJzdXJmYWNlIHdhdGVyIiwgc291cmNlKSkgJT4lIA0KICAgICAgICAgICAgICBtdXRhdGUodGFyZ2V0ID0gaWZlbHNlKHRhcmdldCA9PSAiaW5kdXN0cnkiLCAiaW5kdXN0cnkgKGVsZWMgZXhjbHVkZWQpIiwgdGFyZ2V0KSksDQogICAgICAgICAgICAiV2F0ZXIgVXNlIGJ5IFNvdXJjZSwgQmFzaW4sIENhdGVnb3J5LCBTZWN0b3IsIGFuZCBUZWNobm9sb2d5LCBhbmQgQmFzaW4iKQ0KICANCnBsb3Rfc2Fua2V5KHJiaW5kKGRmX3dhdGVyV2l0aGRyYXdhbHNCeVN0YXRlU2VjdG9yQmFzaW4sIGRmX3dhdGVyV2l0aGRyYXdhbHNCeVdhdGVyU291cmNlLCB3YXRjYXRlZ29yeV9zZWN0b3JfdXNlLCANCiAgICAgICAgICAgICAgICAgIHdhdGNhdGVnb3J5X3N1YnNlY3Rvcl91c2UgJT4lIA0KICAgICAgICAgICAgICAgICAgICAjIGFkZCBoeWRybyBmb3IgcmNwNDVjb29sZXJfc3NwMyBzY2VuYXJpbyBhbmQgeWVhciAyMDUwDQogICAgICAgICAgICAgICAgICAgIGFkZF9yb3coc2NlbmFyaW8gPSAicmNwNDVjb29sZXJfc3NwMyIsIHNvdXJjZSA9ICJlbGVjdHJpY2l0eSIsIHRhcmdldCA9ICJoeWRybyIsIHllYXIgPSAyMDUwLCB2YWx1ZSA9IDAuOTk1ICogMzA2MCAqIDFlLTMpLA0KICAgICAgICAgICAgICAgICAgd2F0ZXJFbmR1c2VCeVRlY2gpICU+JSByZW5hbWVfd2F0ZXJfdXNlX2NhdGVnb3JpZXMoKSAlPiUgDQogICAgICAgICAgICAgIG11dGF0ZShzb3VyY2UgPSBpZmVsc2Uoc291cmNlID09ICJydW5vZmYiLCAic3VyZmFjZSB3YXRlciIsIHNvdXJjZSkpICU+JSANCiAgICAgICAgICAgICAgbXV0YXRlKHRhcmdldCA9IGlmZWxzZSh0YXJnZXQgPT0gImluZHVzdHJ5IiwgImluZHVzdHJ5IChlbGVjIGV4Y2x1ZGVkKSIsIHRhcmdldCkpLA0KICAgICAgICAgICAgIldhdGVyIFVzZSBieSBTb3VyY2UsIEJhc2luLCBDYXRlZ29yeSwgU2VjdG9yLCBhbmQgVGVjaG5vbG9neSwgYW5kIEJhc2luIikNCiAgDQoNCiMgVE9ETzogDQojIGxhYmVscw0KIyB0aW1lDQojIHNjZW5hcmlvcw0KIyBpbmR1c3RyeSAoZWxlYyBleGNsdWRlZCkNCiMgcmVsYWJlbCB0ZCBzZWN0b3JzIA0KIyBydW5vZmYgPSBzdXJmYWNlIHdhdGVyIA0KIyBhbm5vdGF0aW9ucyBmb3IgbGV2ZWxzIChiYXNpbnM6IEhVQzIpDQojIGNhbiBjb2xvcnMgdGhlIG1hcCBhcyB0aGUgcGxvdGx5IGJhc2lucyANCiMgYXZvaWQgcmVwZWF0aW5nIGNvbG9ycw0KYGBgDQoNCg0KYGBgIHtyIGZpZy53aWR0aD05LCB3YXJuaW5nPUZBTFNFfQ0KZWxlY0dlbkJ5R2VuVGVjaENvb2xpbmdUZWNoX2dVU0EgPC0gZ2V0UXVlcnkoaW0zX2VwcmksICJlbGVjIGdlbiBieSBnZW4gdGVjaCBhbmQgY29vbGluZyB0ZWNoIChpbmNsIGNvZ2VuKSIpICU+JSBmaWx0ZXJfQ09OVVNyZWdpb25zKCkNCmVsZWNHZW5CeUdlblRlY2hDb29saW5nVGVjaCA8LSBnZXRRdWVyeShpbTNfZXByaSwgImVsZWMgZ2VuIGJ5IGdlbiB0ZWNoIGFuZCBjb29saW5nIHRlY2giKSAlPiUgZmlsdGVyX0NPTlVTcmVnaW9ucygpDQpoeWRyb193YXRlcl9yZXEgPC0gZWxlY0dlbkJ5R2VuVGVjaENvb2xpbmdUZWNoICU+JQ0KICAgIGZpbHRlcihzdWJzZWN0b3IgPT0gImh5ZHJvIikgJT4lDQogICAgZ3JvdXBfYnkoc2NlbmFyaW8sIHN1YnNlY3Rvciwgb3V0cHV0LCB5ZWFyKSAlPiUNCiAgICBzdW1tYXJpc2UodmFsdWUgPSBzdW0odmFsdWUpKSAlPiUgdW5ncm91cCgpICU+JSANCiAgbXV0YXRlKHNvdXJjZSA9ICJ3YXRlcl90ZF9lbGVjX1ciLA0KICAgICAgICAgaHlkcm9fd2F0ZXJfcmVxID0gdmFsdWUgKiAzMDYwICogMWUtMykgJT4lDQogIHNlbGVjdChzY2VuYXJpbywgc291cmNlLCB0YXJnZXQgPSBzdWJzZWN0b3IsIHllYXIsIHZhbHVlID0gaHlkcm9fd2F0ZXJfcmVxKQ0KYGBgDQoNCiMjIFdhdGVyIERpYWdyYW0gZm9yIFVTQQ0KDQpgYGB7ciBmaWcud2lkdGg9MTAsIHdhcm5pbmc9RkFMU0V9DQojIHJlbW92ZSBiYXNpbnMgYW5kIGVsZWN0cmljaXR5IGFnZ3JlZ2F0aW9ucyAob25seSBrZWVwIHRlY2hub2xvZ2llcykNCg0KIyAxLiBwcmVwYXJlIHJlc291cmNlcyANCg0KZGVzYWxfdG90YWxVU0EgPC0gd2F0ZXJXaXRoZHJhd2Fsc0J5U3RhdGVTZWN0b3JCYXNpbiAlPiUgDQogICAgZmlsdGVyKHJlZ2lvbiAhPSAiVVNBIikgJT4lIA0KICAgIGZpbHRlcih0ZWNobm9sb2d5ID09ICJkZXNhbGluYXRpb24iKSAlPiUgDQogICAgZ3JvdXBfYnkoc2NlbmFyaW8sIHNlY3RvciwgdGVjaG5vbG9neSwgeWVhcikgJT4lDQogICAgc3VtbWFyaXNlKHZhbHVlID0gc3VtKHZhbHVlKSkgJT4lIHVuZ3JvdXAoKSAlPiUNCiAgICBzZWxlY3Qoc2NlbmFyaW8sIHNvdXJjZSA9IHRlY2hub2xvZ3ksIHRhcmdldCA9IHNlY3RvciwgeWVhciwgdmFsdWUpDQoNCiMgY3JlYXRlIHN1cmZhY2UgdG8gZ3JvdW5kd2F0ZXIgc2hhcmVzIGJ5IGJhc2luIGFuZCBhcHBseSB0aG9zZSB0byB1c2UgY2F0ZWdvcmllcyB0byBkZXRlcm1pbmUgYW1vdW50IG9mIHN1cmZhY2UgYW5kIGdyb3VuZHdhdGVyIHVzZWQgZm9yIGVhY2ggZGVtYW5kIA0KIyANCiMgdGhpcyBjYWxjdWxhdGVzIGF2YWlsYWJpbHR5IHNoYXJlcyAod2hpY2ggYXJlIG5vdCByZWFsbHkgcmVsZXZhbnQgYmVjYXN1ZSB3ZSBuZWVkIHdpdGhkcmF3YWwgc2hhcmVzKQ0KIyB0b3RhbFdhdGVyQXZhaWxhYmlsaXR5X1VTQSA8LSByYmluZCgNCiMgICBiYXNpbkxldmVsQXZhaWxhYmxlUnVub2ZmICU+JSBmaWx0ZXJfYmFzaW5fcmVzb3VyY2UoYmFzaW4pICU+JSByZW1vdmVfd2F0ZXJfd2l0aGRyYXdhbHNfc3RyaW5nKGJhc2luKSAlPiUgDQojICAgICAjIHdlIG1heSBoYXZlIHRvIHN3aXRjaCB0aGUgc291cmNlIGFuZCB0YXJnZXQgaGVyZSB0byBzdGFydCBmcm9tIHdhdGVyIHNvdXJjZXMgYW5kIGdvIHRvIGJhc2lucw0KIyAgICAgc2VsZWN0KHNjZW5hcmlvLCB0YXJnZXQgPSBiYXNpbiwgc291cmNlID0gc3VicmVzb3VyY2UsIHllYXIsIHZhbHVlKSwNCiMgICB0b3RhbEdyb3VuZHdhdGVyQXZhaWxhYmxlICU+JSANCiMgICAgIGZpbHRlcl9iYXNpbl9yZXNvdXJjZSgpICU+JSByZW1vdmVfd2F0ZXJfd2l0aGRyYXdhbHNfc3RyaW5nKCkgJT4lIA0KIyAgICAgZmlsdGVyKGdyYWRlICE9ICJncmFkZSBoaXN0IikgJT4lIA0KIyAgICAgZ3JvdXBfYnkoc2NlbmFyaW8sIHJlc291cmNlLCBzdWJyZXNvdXJjZSwgeWVhcikgJT4lDQojICAgICBzdW1tYXJpc2UodmFsdWUgPSBzdW0odmFsdWUpKSAlPiUgdW5ncm91cCgpICU+JQ0KIyAgICAgc2VsZWN0KHNjZW5hcmlvLCB0YXJnZXQgPSByZXNvdXJjZSwgc291cmNlID0gc3VicmVzb3VyY2UsIHllYXIsIHZhbHVlKQ0KIyApICU+JSBncm91cF9ieShzY2VuYXJpbywgc291cmNlLCB5ZWFyKSAlPiUNCiMgICAgIHN1bW1hcmlzZSh2YWx1ZSA9IHN1bSh2YWx1ZSkpICU+JSB1bmdyb3VwKCkgDQoNCg0Kd2F0ZXJXaXRoZHJhd2Fsc0J5V2F0ZXJTb3VyY2Vfc2hhcmVzX2J5YmFzaW4gPC0gd2F0ZXJXaXRoZHJhd2Fsc0J5V2F0ZXJTb3VyY2UgJT4lIA0KICBmaWx0ZXJfYmFzaW5fcmVzb3VyY2UoKSAlPiUNCiAgcmVtb3ZlX3dhdGVyX3dpdGhkcmF3YWxzX3N0cmluZygpICU+JQ0KICBncm91cF9ieShzY2VuYXJpbywgcmVnaW9uLCByZXNvdXJjZSwgeWVhcikgJT4lIG11dGF0ZShzaGFyZSA9IHZhbHVlIC8gc3VtKHZhbHVlKSkgJT4lIHVuZ3JvdXAoKQ0KDQpkYXRhdGFibGUod2F0ZXJXaXRoZHJhd2Fsc0J5V2F0ZXJTb3VyY2Vfc2hhcmVzX2J5YmFzaW4sIGZpbHRlciA9ICJ0b3AiKQ0KDQoNCndhdGVyV2l0aGRyYXdhbHNCeVN0YXRlU2VjdG9yQmFzaW5fc291cmNlIDwtIHdhdGVyV2l0aGRyYXdhbHNCeVN0YXRlU2VjdG9yQmFzaW4gJT4lIA0KICAjIGZpbHRlcihzY2VuYXJpbyA9PSAicmNwODVjb29sZXJfc3NwNSIsIHllYXIgPT0gIjIwNTAiLCBzZWN0b3IgPT0gIndhdGVyX3RkX2FuX1ciKSAlPiUNCiAgZmlsdGVyKHJlZ2lvbiAhPSAiVVNBIikgJT4lICMgZXhjbHVkZSBVU0EgbGV2ZWwgZGF0YSBiZWNhdXNlIGl0IGFnZ3JlZ2F0ZWQgdXAgZnJvbSBiYXNpbiBsZXZlbCBkYXRhLCBidXQgbGFja3MgdGhlIHRlY2hub2xvZ3kgZGV0YWlsIChuYW1lIG9mIHRoZSBiYXNpbiBoZXJlKQ0KICBmaWx0ZXJfQ09OVVNyZWdpb25zKHRlY2hub2xvZ3ksIGJhc2luc19jb251c19yZXNvdXJjZSkgJT4lICMgbm90IHN1cmUgd2h5IG5vbkNPTlVTIGJhc2lucyBoYXZlIGNyZXB0IGluIGhlcmUgYXQgdGhlIHRlY2hub2xvZ3kgbGV2ZWwsIGJ1dCByZW1vdmUgdGhlbSANCiAgZmlsdGVyKHRlY2hub2xvZ3kgIT0gImRlc2FsaW5hdGlvbiIpICU+JSAjIHdlIGhhdmUgZGVzYWxpbmF0aW9uIGF0IHRoZSBiYXNpbiBsZXZlbCBpbiB0aGUgcHJldmlvdXMgcGxvdCANCiAgcmVwbGFjZV9hZnRlcl9pcnJfc3RyaW5nKCkgJT4lICMgaWYgdGhpcyBpcyByZW1vdmVkLCBlYWNoIGJhc2luIHdpbGwgc3VwcGx5IHRvIGl0J3Mgb3duIGlycmlnYXRpb24gZGVtYW5kDQogIGdyb3VwX2J5KHNjZW5hcmlvLCBzZWN0b3IsIHRlY2hub2xvZ3ksIHllYXIpICU+JQ0KICBzdW1tYXJpc2UodmFsdWUgPSBzdW0odmFsdWUpKSAlPiUgdW5ncm91cCgpICU+JQ0KICBzZWxlY3Qoc2NlbmFyaW8sIHNvdXJjZSA9IHRlY2hub2xvZ3ksIHRhcmdldCA9IHNlY3RvciwgeWVhciwgZGVtYW5kX3dpdGhkcmF3ID0gdmFsdWUpICU+JSANCiAgbGVmdF9qb2luKHdhdGVyV2l0aGRyYXdhbHNCeVdhdGVyU291cmNlX3NoYXJlc19ieWJhc2luLCBieSA9IGMoInNjZW5hcmlvIiwgInNvdXJjZSIgPSAicmVzb3VyY2UiLCAieWVhciIpKSAlPiUgDQogIG11dGF0ZShzb3VyY2VfZGlzYWdnID0gZGVtYW5kX3dpdGhkcmF3ICogc2hhcmUpIA0KDQpkYXRhdGFibGUod2F0ZXJXaXRoZHJhd2Fsc0J5U3RhdGVTZWN0b3JCYXNpbl9zb3VyY2UsIGZpbHRlciA9ICJ0b3AiKQ0KYGBgDQoNCg0KYGBge3IgZmlnLndpZHRoPTEwLCB3YXJuaW5nPUZBTFNFfQ0KIyBjcmVhdGUgMyB3YXkgc2hhcmVzIGFtb25nIHJ1bm9mZiBndyBhbmQgZGVzYWwgYnkgdXNpbmcgIGRlc2FsIGZyb20gd2F0ZXJXaXRoZHJhd2Fsc0J5U3RhdGVTZWN0b3JCYXNpbiBhbmQgcnVub2ZmIGFuZCBndyBmcm9tIHdhdGVyV2l0aGRyYXdhbHNCeVdhdGVyU291cmNlDQpnd1J1bm9mZkRlc2FsU2hhcmVzIDwtIHdhdGVyV2l0aGRyYXdhbHNCeVdhdGVyU291cmNlICU+JSANCiAgZmlsdGVyX2Jhc2luX3Jlc291cmNlKCkgJT4lDQogIHJlbW92ZV93YXRlcl93aXRoZHJhd2Fsc19zdHJpbmcoKSAlPiUgc2VsZWN0KCFjKCJVbml0cyIsICJyZWdpb24iKSkgJT4lIA0KICByYmluZCh3YXRlcldpdGhkcmF3YWxzQnlTdGF0ZVNlY3RvckJhc2luICU+JSANCiAgICAgICAgICBmaWx0ZXIocmVnaW9uICE9ICJVU0EiKSAlPiUgDQogICAgICAgICAgZmlsdGVyKHRlY2hub2xvZ3kgPT0gImRlc2FsaW5hdGlvbiIpICU+JSANCiAgICAgICAgICBncm91cF9ieShzY2VuYXJpbywgc3Vic2VjdG9yLCB0ZWNobm9sb2d5LCB5ZWFyKSAlPiUNCiAgICAgICAgICBzdW1tYXJpc2UodmFsdWUgPSBzdW0odmFsdWUpKSAlPiUgdW5ncm91cCgpICU+JQ0KICAgICAgICAgIHNlbGVjdChzY2VuYXJpbywgc3VicmVzb3VyY2UgPSB0ZWNobm9sb2d5LCByZXNvdXJjZSA9IHN1YnNlY3RvciwgeWVhciwgdmFsdWUpDQogICkgJT4lIGdyb3VwX2J5KHNjZW5hcmlvLCByZXNvdXJjZSwgeWVhcikgJT4lIG11dGF0ZShzaGFyZSA9IHZhbHVlIC8gc3VtKHZhbHVlKSkgJT4lIHVuZ3JvdXAoKQ0KDQp3YXRlcldpdGhkcmF3YWxzQnlTdGF0ZVNlY3RvckJhc2luX3NvdXJjZV8zIDwtIHdhdGVyV2l0aGRyYXdhbHNCeVN0YXRlU2VjdG9yQmFzaW4gJT4lIA0KICAjIGZpbHRlcihzY2VuYXJpbyA9PSAicmNwODVjb29sZXJfc3NwNSIsIHllYXIgPT0gIjIwNTAiLCBzZWN0b3IgPT0gIndhdGVyX3RkX2FuX1ciKSAlPiUNCiAgZmlsdGVyKHJlZ2lvbiAhPSAiVVNBIikgJT4lICMgZXhjbHVkZSBVU0EgbGV2ZWwgZGF0YSBiZWNhdXNlIGl0IGFnZ3JlZ2F0ZWQgdXAgZnJvbSBiYXNpbiBsZXZlbCBkYXRhLCBidXQgbGFja3MgdGhlIHRlY2hub2xvZ3kgZGV0YWlsIChuYW1lIG9mIHRoZSBiYXNpbiBoZXJlKQ0KICBmaWx0ZXJfQ09OVVNyZWdpb25zKHRlY2hub2xvZ3ksIGJhc2luc19jb251c19yZXNvdXJjZSkgJT4lICMgbm90IHN1cmUgd2h5IG5vbkNPTlVTIGJhc2lucyBoYXZlIGNyZXB0IGluIGhlcmUgYXQgdGhlIHRlY2hub2xvZ3kgbGV2ZWwsIGJ1dCByZW1vdmUgdGhlbSANCiAgZmlsdGVyKHRlY2hub2xvZ3kgIT0gImRlc2FsaW5hdGlvbiIpICU+JSAjIHdlIGhhdmUgZGVzYWxpbmF0aW9uIGF0IHRoZSBiYXNpbiBsZXZlbCBpbiB0aGUgcHJldmlvdXMgcGxvdCANCiAgcmVwbGFjZV9hZnRlcl9pcnJfc3RyaW5nKCkgJT4lICMgaWYgdGhpcyBpcyByZW1vdmVkLCBlYWNoIGJhc2luIHdpbGwgc3VwcGx5IHRvIGl0J3Mgb3duIGlycmlnYXRpb24gZGVtYW5kDQogIGdyb3VwX2J5KHNjZW5hcmlvLCBzZWN0b3IsIHRlY2hub2xvZ3ksIHllYXIpICU+JQ0KICBzdW1tYXJpc2UodmFsdWUgPSBzdW0odmFsdWUpKSAlPiUgdW5ncm91cCgpICU+JQ0KICBzZWxlY3Qoc2NlbmFyaW8sIHNvdXJjZSA9IHRlY2hub2xvZ3ksIHRhcmdldCA9IHNlY3RvciwgeWVhciwgZGVtYW5kX3dpdGhkcmF3ID0gdmFsdWUpICU+JSANCiAgbGVmdF9qb2luKGd3UnVub2ZmRGVzYWxTaGFyZXMsIGJ5ID0gYygic2NlbmFyaW8iLCAic291cmNlIiA9ICJyZXNvdXJjZSIsICJ5ZWFyIikpICU+JSANCiAgbXV0YXRlKHNvdXJjZV9kaXNhZ2cgPSBkZW1hbmRfd2l0aGRyYXcgKiBzaGFyZSkgDQoNCg0Kd2F0ZXJTb3VyY2VVc2VDYXRlZ29yaWVzMyA8LSB3YXRlcldpdGhkcmF3YWxzQnlTdGF0ZVNlY3RvckJhc2luX3NvdXJjZV8zICU+JSANCiAgZ3JvdXBfYnkoc2NlbmFyaW8sIHN1YnJlc291cmNlLCB0YXJnZXQsIHllYXIpICU+JSANCiAgc3VtbWFyaXNlKHZhbHVlID0gc3VtKHNvdXJjZV9kaXNhZ2cpKSAlPiUgdW5ncm91cCgpICU+JSANCiAgc2VsZWN0KHNjZW5hcmlvLCBzb3VyY2UgPSBzdWJyZXNvdXJjZSwgdGFyZ2V0LCB5ZWFyLCB2YWx1ZSkgJT4lIA0KICAjIG5vdGUgd2UgYXJlIGFnZ3JlZ2F0aW5nIHVwIGJhc2luLWxldmVsIGlycmlnYXRpb24gZnJvbSBkZXNhbGluYXRpb24gaGVyZSANCiAgcmJpbmQoZGVzYWxfdG90YWxVU0EgJT4lIHJlcGxhY2VfYWZ0ZXJfaXJyX3N0cmluZyh0YXJnZXQpICU+JSANCiAgICAgICAgICBncm91cF9ieShzY2VuYXJpbywgc291cmNlLCB0YXJnZXQsIHllYXIpICU+JSBzdW1tYXJpc2UodmFsdWUgPSBzdW0odmFsdWUpKSAlPiUgdW5ncm91cCgpDQogICAgICAgICkgDQoNCnBsb3Rfc2Fua2V5KHdhdGVyU291cmNlVXNlQ2F0ZWdvcmllczMsICJXYXRlciBTb3VyY2UgYW5kIFVzZSBDYXRlZ29yeSIpICANCnBsb3Rfc2Fua2V5KHJiaW5kKHdhdGVyU291cmNlVXNlQ2F0ZWdvcmllczMsIHdhdGVyQ2F0ZW9ncnlUZWNoKSwgIldhdGVyIFNvdXJjZSwgVXNlIENhdGVnb3J5LCBhbmQgRW5kLVVzZSIpDQoNCiMgQ09OTENVU0lPTjogVEhJUyBJUyBFWEFDVExZIFRIRSBTQU1FIEFTIFRIRSBPTkUgUFJFUEFSRSBXSUhUT1VUIDMgV0FZIFNIQVJFUyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KDQpgYGANCg0KYGBge3IgZmlnLndpZHRoPTEwLCB3YXJuaW5nPUZBTFNFfQ0KIyBVUyBsZXZlbCBzdXBwbHkgYW5kIGRlbWFuZA0Kd2F0ZXJTb3VyY2VVc2VDYXRlZ29yaWVzIDwtIHdhdGVyV2l0aGRyYXdhbHNCeVN0YXRlU2VjdG9yQmFzaW5fc291cmNlICU+JSANCiAgZ3JvdXBfYnkoc2NlbmFyaW8sIHN1YnJlc291cmNlLCB0YXJnZXQsIHllYXIpICU+JSANCiAgc3VtbWFyaXNlKHZhbHVlID0gc3VtKHNvdXJjZV9kaXNhZ2cpKSAlPiUgdW5ncm91cCgpICU+JSANCiAgc2VsZWN0KHNjZW5hcmlvLCBzb3VyY2UgPSBzdWJyZXNvdXJjZSwgdGFyZ2V0LCB5ZWFyLCB2YWx1ZSkgJT4lIA0KICAjIG5vdGUgd2UgYXJlIGFnZ3JlZ2F0aW5nIHVwIGJhc2luLWxldmVsIGlycmlnYXRpb24gZnJvbSBkZXNhbGluYXRpb24gaGVyZSANCiAgcmJpbmQoZGVzYWxfdG90YWxVU0EgJT4lIHJlcGxhY2VfYWZ0ZXJfaXJyX3N0cmluZyh0YXJnZXQpICU+JSANCiAgICAgICAgICBncm91cF9ieShzY2VuYXJpbywgc291cmNlLCB0YXJnZXQsIHllYXIpICU+JSBzdW1tYXJpc2UodmFsdWUgPSBzdW0odmFsdWUpKSAlPiUgdW5ncm91cCgpDQogICAgICAgICkgDQoNCnBsb3Rfc2Fua2V5KHdhdGVyU291cmNlVXNlQ2F0ZWdvcmllcywgIldhdGVyIFNvdXJjZSBhbmQgVXNlIENhdGVnb3J5IikgICANCg0KYGBgDQoNCmBgYHtyIGZpZy53aWR0aD0xMCwgd2FybmluZz1GQUxTRX0NCiMgd2F0ZXIgc291cmNlLCB1c2UgY2F0ZWdvcnksIGFuZCBlbmQtdXNlIA0Kd2F0ZXJDYXRlb2dyeVRlY2ggPC0gDQogICMgd2Ugd2lsbCB1c2UgZGlmZmVyZW50IGRldGFpbHMgZm9yIGVhY2ggdXNlIGNhdGVnb3J5IA0KICByYmluZCgNCiAgICAjIGVsZWN0cmljaXR5IG9uIHRlY2ggbGV2ZWwNCiAgICB3YXRlcldpdGhkcmF3YWxzQnlUZWNoX3dhdENhdCAlPiUgDQogICAgICBmaWx0ZXIod2F0Y2F0ZWdvcnkgPT0gIndhdGVyX3RkX2VsZWNfVyIpICU+JSANCiAgICAgIGNsZWFuX2Nvb2xpbmdfdGVjaCgidGVjaG5vbG9neSIsIGNvb2xpbmdfdGVjaHMsIGNvb2xpbmdfdGVjaHNfeWVhcnMpICU+JQ0KICAgICAgZ3JvdXBfYnkoc2NlbmFyaW8sIHdhdGNhdGVnb3J5LCB0ZWNobm9sb2d5LCB5ZWFyKSAlPiUNCiAgICAgIHN1bW1hcmlzZSh2YWx1ZSA9IHN1bSh2YWx1ZSkpICU+JSB1bmdyb3VwKCkgJT4lIA0KICAgICAgc2VsZWN0KHNjZW5hcmlvLCBzb3VyY2UgPSB3YXRjYXRlZ29yeSwgdGFyZ2V0ID0gdGVjaG5vbG9neSwgeWVhciwgdmFsdWUpDQogICAgLCANCiAgICAjIGV2ZXJ5dGhpbmcgZWxzZSBvbiBzZWN0b3IgbGV2ZWwgDQogICAgd2F0ZXJXaXRoZHJhd2Fsc0J5VGVjaF93YXRDYXQgJT4lIA0KICAgICAgZmlsdGVyKHdhdGNhdGVnb3J5ICE9ICJ3YXRlcl90ZF9lbGVjX1ciKSAlPiUgDQogICAgICBncm91cF9ieShzY2VuYXJpbywgd2F0Y2F0ZWdvcnksIHNlY3RvciwgeWVhcikgJT4lDQogICAgICBzdW1tYXJpc2UodmFsdWUgPSBzdW0odmFsdWUpKSAlPiUgdW5ncm91cCgpICU+JQ0KICAgICAgc2VsZWN0KHNjZW5hcmlvLCBzb3VyY2UgPSB3YXRjYXRlZ29yeSwgdGFyZ2V0ID0gc2VjdG9yLCB5ZWFyLCB2YWx1ZSkNCiAgKQ0KDQpwbG90X3NhbmtleShyYmluZCh3YXRlclNvdXJjZVVzZUNhdGVnb3JpZXMsIHdhdGVyQ2F0ZW9ncnlUZWNoKSwgIldhdGVyIFNvdXJjZSwgVXNlIENhdGVnb3J5LCBhbmQgRW5kLVVzZSIpDQpgYGANCg0KDQpgYGB7ciBmaWcud2lkdGg9MTAsIHdhcm5pbmc9RkFMU0V9DQojIHdhdGVyIHNvdXJjZSwgYmFzaW4sIHVzZSBjYXRlZ29yeSwgYW5kIGVuZC11c2UNCnBsb3Rfc2Fua2V5KHJiaW5kKGRmX3dhdGVyV2l0aGRyYXdhbHNCeVdhdGVyU291cmNlLCBkZl93YXRlcldpdGhkcmF3YWxzQnlTdGF0ZVNlY3RvckJhc2luLCB3YXRlckNhdGVvZ3J5VGVjaCwgaHlkcm9fd2F0ZXJfcmVxKSwgIldhdGVyIFNvdXJjZSwgQmFzaW4sIFVzZSBDYXRlZ29yeSwgYW5kIEVuZC1Vc2UiKQ0KYGBgDQoNCg0KYGBge3IgZmlnLndpZHRoPTEwLCB3YXJuaW5nPUZBTFNFfQ0KIyBTV0FQUEVEIGJhc2luczogd2F0ZXIgc291cmNlLCBiYXNpbiwgdXNlIGNhdGVnb3J5LCBhbmQgZW5kLXVzZQ0Kd2F0ZXJfc291cmNlX3RhcmdldCA8LSByYmluZChkZl93YXRlcldpdGhkcmF3YWxzQnlXYXRlclNvdXJjZSAlPiUgc3dhcF9zb3VyY2VfdGFyZ2V0KCksIA0KICAgICAgICAgICAgICAgICAgd2F0ZXJTb3VyY2VVc2VDYXRlZ29yaWVzLA0KICAgICAgICAgICAgICAgICAgd2F0ZXJDYXRlb2dyeVRlY2gsIGh5ZHJvX3dhdGVyX3JlcSkgJT4lIA0KICBjb21wbGV0ZShzY2VuYXJpbywgeWVhciwgbmVzdGluZyhzb3VyY2UsIHRhcmdldCksIGZpbGwgPSBsaXN0KHZhbHVlID0gMCkpICU+JSBtdXRhdGUodW5pdHMgPSAia20zIikgJT4lIA0KICBzZWxlY3Qoc2NlbmFyaW8sIHNvdXJjZSwgdGFyZ2V0LCB5ZWFyLCB2YWx1ZSwgdW5pdHMpDQoNCnBsb3Rfc2Fua2V5KHdhdGVyX3NvdXJjZV90YXJnZXQsICJXYXRlciBTb3VyY2UsIEJhc2luLCBVc2UgQ2F0ZWdvcnksIGFuZCBFbmQtVXNlIikNCg0Kd3JpdGVfY3N2KHdhdGVyX3NvdXJjZV90YXJnZXQgLCBwYXN0ZTAoIi4uLyIsIGRhdGFfZGlyLCAid2F0ZXJfc291cmNlX3RhcmdldC5jc3YiKSkNCmBgYA0KDQoNCg0KDQpgYGB7ciBmaWcud2lkdGg9MTAsIHdhcm5pbmc9RkFMU0V9DQojIHdhdGVyIHNvdXJjZSwgYmFzaW4sIHVzZSBjYXRlZ29yeSwgYW5kIGVuZC11c2UgV0lUSCBCRVRURVIgQ09MT1JTIA0KDQp3YXRlclNvdXJjZUJhc2luc0NhdGVnb3JpZXNVc2VfY29sb3JzIDwtIHJlYWRfY3N2KHBhc3RlMCgiLi4vIiwgZGF0YV9kaXIsICJ3YXRlclNvdXJjZUJhc2luc0NhdGVnb3JpZXNVc2UuY3N2IikpDQoNCnBsb3Rfc2Fua2V5KHdhdGVyU291cmNlQmFzaW5zQ2F0ZWdvcmllc1VzZV9jb2xvcnMsICJXYXRlciBTb3VyY2UsIEJhc2luLCBVc2UgQ2F0ZWdvcnksIGFuZCBFbmQtVXNlIikNCmBgYA0KDQoNCmBgYHtyIGZpZy53aWR0aD0xMCwgd2FybmluZz1GQUxTRX0NCiMgQ29tYmluZSBzb3VyY2UgYW5kIHRhcmdldCB0byBnZXQgdW5pcXVlIG5vZGVzIGFuZCB0aGVpciBjb2xvcnMNCm5vZGVzIDwtIHdhdGVyU291cmNlQmFzaW5zQ2F0ZWdvcmllc1VzZV9jb2xvcnMgJT4lDQogIHNlbGVjdChzb3VyY2UsIHNvdXJjZV9jb2xvcikgJT4lDQogIHJlbmFtZShub2RlID0gc291cmNlLCBub2RlX2NvbG9yID0gc291cmNlX2NvbG9yKSAlPiUNCiAgYmluZF9yb3dzKA0KICAgIHdhdGVyU291cmNlQmFzaW5zQ2F0ZWdvcmllc1VzZV9jb2xvcnMgJT4lDQogICAgICBzZWxlY3QodGFyZ2V0LCB0YXJnZXRfY29sb3IpICU+JQ0KICAgICAgcmVuYW1lKG5vZGUgPSB0YXJnZXQsIG5vZGVfY29sb3IgPSB0YXJnZXRfY29sb3IpDQogICkgJT4lDQogIGRpc3RpbmN0KCkNCg0KIyBBZGQgY29sb3IgZGlyZWN0bHkgdG8gbm9kZSBsYWJlbHMNCm5vZGVfbGFiZWxzIDwtIHVuaXF1ZShjKHdhdGVyU291cmNlQmFzaW5zQ2F0ZWdvcmllc1VzZV9jb2xvcnMkc291cmNlLCANCiAgICAgICAgICAgICAgICAgICAgICAgIHdhdGVyU291cmNlQmFzaW5zQ2F0ZWdvcmllc1VzZV9jb2xvcnMkdGFyZ2V0KSkNCg0KIyBNYXAgbm9kZSBjb2xvcnMgdG8gbm9kZSBsYWJlbHMNCm5vZGVfY29sb3JzIDwtIG5vZGVzJG5vZGVfY29sb3JbbWF0Y2gobm9kZV9sYWJlbHMsIG5vZGVzJG5vZGUpXQ0KYGBgDQoNCg0KYGBge3IgZmlnLndpZHRoPTEwLCB3YXJuaW5nPUZBTFNFfQ0KdW5pcXVlKHdhdGVyU291cmNlQmFzaW5zQ2F0ZWdvcmllc1VzZV9jb2xvcnNbYygic291cmNlIiwgInNvdXJjZV9jb2xvciIpXSkkc291cmNlX2NvbG9yW21hdGNoKG5vZGVfbGFiZWxzLCB1bmlxdWUod2F0ZXJTb3VyY2VCYXNpbnNDYXRlZ29yaWVzVXNlX2NvbG9ycyRzb3VyY2UpKV0NCg0KDQpgYGANCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCiMjIEVuZXJneSBTYW5rZXkNCg0KT3ZlcmFsbCBpbmZvcm1hdGlvbiByZXF1aXJlZDoNCg0KLSByZXNvdXJjZSBwcm9kdWN0aW9uIChjb2FsLCBnYXMsIG9pbCBldGMpDQotIGVuZXJneSBpbnB1dHMgdG8gZWxlY3RyaWNpdHkgZ2VuZXJhdGlvbiANCiAgICAtIGlucHV0IGlzIHJlc291cmNlIA0KICAgIC0gDQotIGVsZWN0cmljaXR5IGdlbmVyYXRpb24gDQogICAgLSANCi0gZWxlY3RyaWNpdHkgdXNlIGJ5IGNhdGVnb3JpZXMgDQogICAgLSANCi0gZWxlY3RyaWNpdHkgdXNlIGJ5IGVuZCB1c2VzDQogICAgLSANCg0KDQpRdWVyaWVzOiANCg0KLSBgZWxlYyBlbmVyZ3kgaW5wdXQgYnkgZWxlYyBnZW4gdGVjaCBhbmQgY29vbGluZyB0ZWNoYA0KLSBgZWxlYyB3YXRlciB3aXRoZHJhd2FscyBieSBnZW4gdGVjaCBhbmQgY29vbGluZyB0ZWNoYA0KLSBgZWxlYyBnZW4gYnkgZ2VuIHRlY2ggYW5kIGNvb2xpbmcgdGVjaCAoaW5jbCBjb2dlbilgDQotIGBlbGVjIGVuZXJneSBpbnB1dCBieSBlbGVjIGdlbiB0ZWNoYA0KLSBgZWxlYyBnZW4gYnkgZ2VuIHRlY2ggYW5kIGNvb2xpbmcgdGVjaGANCi0gYGVsZWMgd2F0ZXIgd2l0aGRyYXdhbHMgYnkgZ2VuIHRlY2hgDQotIGBlbGVjIHRkIGlucHV0cyBhbmQgb3V0cHV0c2ANCi0gYGVsZWMgY29uc3VtcHRpb24gYnkgZGVtYW5kIHNlY3RvcmANCg0KDQpgYGB7ciBmaWcud2lkdGg9OCwgd2FybmluZz1GQUxTRX0NCiMgcmVhZCBxdWVyaWVzIA0KIyBHQ0FNLVVTQSBzcGVjaWZpYyBxdWVyaWVzIA0KZWxlY0VuZXJneUlucHV0QnlFbGVjR2VuVGVjaENvb2xpbmdUZWNoX2dVU0EgPC0gZ2V0UXVlcnkoaW0zX2VwcmksICJlbGVjIGVuZXJneSBpbnB1dCBieSBlbGVjIGdlbiB0ZWNoIGFuZCBjb29saW5nIHRlY2giKSAlPiUgZmlsdGVyX0NPTlVTcmVnaW9ucygpDQplbGVjV2F0ZXJXaXRoZHJhd0J5RWxlY0dlblRlY2hDb29saW5nVGVjaF9nVVNBIDwtIGdldFF1ZXJ5KGltM19lcHJpLCAiZWxlYyB3YXRlciB3aXRoZHJhd2FscyBieSBnZW4gdGVjaCBhbmQgY29vbGluZyB0ZWNoIikgJT4lIGZpbHRlcl9DT05VU3JlZ2lvbnMoKQ0KZWxlY0dlbkJ5R2VuVGVjaENvb2xpbmdUZWNoX2dVU0EgPC0gZ2V0UXVlcnkoaW0zX2VwcmksICJlbGVjIGdlbiBieSBnZW4gdGVjaCBhbmQgY29vbGluZyB0ZWNoIChpbmNsIGNvZ2VuKSIpICU+JSBmaWx0ZXJfQ09OVVNyZWdpb25zKCkNCiMgZ2VuZXJpYyBHQ0FNIHF1ZXJpZXMNCmVsZWNFbmVyZ3lJbnB1dEJ5RWxlY0dlblRlY2ggPC0gZ2V0UXVlcnkoaW0zX2VwcmksICJlbGVjIGVuZXJneSBpbnB1dCBieSBlbGVjIGdlbiB0ZWNoIikgJT4lIGZpbHRlcl9DT05VU3JlZ2lvbnMoKQ0KZWxlY0dlbkJ5R2VuVGVjaENvb2xpbmdUZWNoIDwtIGdldFF1ZXJ5KGltM19lcHJpLCAiZWxlYyBnZW4gYnkgZ2VuIHRlY2ggYW5kIGNvb2xpbmcgdGVjaCIpICU+JSBmaWx0ZXJfQ09OVVNyZWdpb25zKCkNCmVsZWNXYXRlcldpdGhkcmF3QnlHZW5UZWNoIDwtIGdldFF1ZXJ5KGltM19lcHJpLCAiZWxlYyB3YXRlciB3aXRoZHJhd2FscyBieSBnZW4gdGVjaCIpICU+JSBmaWx0ZXJfQ09OVVNyZWdpb25zKCkNCmVsZWNURElucHV0c091dHB1dHMgPC0gZ2V0UXVlcnkoaW0zX2VwcmksICJlbGVjIHRkIGlucHV0cyBhbmQgb3V0cHV0cyIpICU+JSBmaWx0ZXJfQ09OVVNyZWdpb25zKCkNCmVsZWNDb25zdW1wdGlvbkJ5RGVtYW5kU2VjdG9yIDwtIGdldFF1ZXJ5KGltM19lcHJpLCAiZWxlYyBjb25zdW1wdGlvbiBieSBkZW1hbmQgc2VjdG9yIikgJT4lIGZpbHRlcl9DT05VU3JlZ2lvbnMoKQ0KYGBgDQoNCmBgYHtyLCBtZXNzc2FnZSA9IFQsIHdhcm5pbmcgPSBGQUxTRX0NCmRhdGFfdGFibGVzX2V3IDwtIGxpc3QoDQogICJlbGVjRW5lcmd5SW5wdXRCeUVsZWNHZW5UZWNoQ29vbGluZ1RlY2hfZ1VTQSIgPSBlbGVjRW5lcmd5SW5wdXRCeUVsZWNHZW5UZWNoQ29vbGluZ1RlY2hfZ1VTQSwNCiAgImVsZWNXYXRlcldpdGhkcmF3QnlFbGVjR2VuVGVjaENvb2xpbmdUZWNoX2dVU0EiID0gZWxlY1dhdGVyV2l0aGRyYXdCeUVsZWNHZW5UZWNoQ29vbGluZ1RlY2hfZ1VTQSwNCiAgImVsZWNHZW5CeUdlblRlY2hDb29saW5nVGVjaF9nVVNBIiA9IGVsZWNHZW5CeUdlblRlY2hDb29saW5nVGVjaF9nVVNBLA0KICAiZWxlY0VuZXJneUlucHV0QnlFbGVjR2VuVGVjaCIgPSBlbGVjRW5lcmd5SW5wdXRCeUVsZWNHZW5UZWNoLA0KICAiZWxlY0dlbkJ5R2VuVGVjaENvb2xpbmdUZWNoIiA9IGVsZWNHZW5CeUdlblRlY2hDb29saW5nVGVjaCwNCiAgImVsZWNXYXRlcldpdGhkcmF3QnlHZW5UZWNoIiA9IGVsZWNXYXRlcldpdGhkcmF3QnlHZW5UZWNoLA0KICAiZWxlY1RESW5wdXRzT3V0cHV0cyIgPSBlbGVjVERJbnB1dHNPdXRwdXRzLA0KICAiZWxlY0NvbnN1bXB0aW9uQnlEZW1hbmRTZWN0b3IiID0gZWxlY0NvbnN1bXB0aW9uQnlEZW1hbmRTZWN0b3INCikNCg0KIyBwcmludCBjb2x1bW4gbmFtZXMgb2YgZWFjaCBkYXRhdGFibGUNCmxhcHBseShkYXRhX3RhYmxlc19ldywgZnVuY3Rpb24oeCkgY29sbmFtZXMoeCkpDQoNCiMgcHJpbnQgdGhlIGZpcnN0IGZldyByb3dzIG9mIGVhY2ggZGF0YXRhYmxlDQpsYXBwbHkoZGF0YV90YWJsZXNfZXcsIGZ1bmN0aW9uKHgpICh4KSkNCmBgYA0KDQoNCmBgYHtyIGZpZy53aWR0aD0xMCwgd2FybmluZz1GQUxTRX0NCmVsZWNfc291cmNlX3RhcmdldCA8LSByYmluZCgNCiAgIyB3YXRlciB3aXRoZHJhd2FscyBieSBlbGVjdHJpY2l0eSBnZW5lcmF0aW9uIHRlY2hub2xvZ3kNCiAgZWxlY1dhdGVyV2l0aGRyYXdCeUdlblRlY2ggJT4lIA0KICAgICMgbXV0YXRlKHZhbHVlID0gdmFsdWUgKiAxZS0xKSAlPiUgIyBjaGFuZ2UgdG8geDEwIGttMyBmb3IgYmV0dGVyIHZpc3VhbHMNCiAgICBjbGVhbl9jb29saW5nX3RlY2goInRlY2hub2xvZ3kiLCBjb29saW5nX3RlY2hzLCBjb29saW5nX3RlY2hzX3llYXJzKSAlPiUNCiAgICBncm91cF9ieShzY2VuYXJpbywgdGVjaG5vbG9neSwgaW5wdXQsIHllYXIpICU+JQ0KICAgIHN1bW1hcmlzZSh2YWx1ZSA9IHN1bSh2YWx1ZSkpICU+JSB1bmdyb3VwKCkgJT4lIA0KICAgIHNlbGVjdChzY2VuYXJpbywgc291cmNlID0gaW5wdXQgLCB0YXJnZXQgPSB0ZWNobm9sb2d5LCB5ZWFyLCB2YWx1ZSkNCiAgLA0KICBlbGVjRW5lcmd5SW5wdXRCeUVsZWNHZW5UZWNoICU+JSANCiAgICBjbGVhbl9jb29saW5nX3RlY2goInRlY2hub2xvZ3kiLCBjb29saW5nX3RlY2hzLCBjb29saW5nX3RlY2hzX3llYXJzKSAlPiUNCiAgICBncm91cF9ieShzY2VuYXJpbywgdGVjaG5vbG9neSwgaW5wdXQsIHllYXIpICU+JQ0KICAgIHN1bW1hcmlzZSh2YWx1ZSA9IHN1bSh2YWx1ZSkpICU+JSB1bmdyb3VwKCkgJT4lIA0KICAgIHNlbGVjdChzY2VuYXJpbywgc291cmNlID0gaW5wdXQgLCB0YXJnZXQgPSB0ZWNobm9sb2d5LCB5ZWFyLCB2YWx1ZSkNCiAgLA0KICAjIGVsZWN0cmljaXR5IGdlbmVyYXRpb24gYnkgdGVjaG5vbG9neQ0KICBlbGVjR2VuQnlHZW5UZWNoQ29vbGluZ1RlY2ggJT4lIA0KICAgIGNsZWFuX2Nvb2xpbmdfdGVjaCgidGVjaG5vbG9neSIsIGNvb2xpbmdfdGVjaHMsIGNvb2xpbmdfdGVjaHNfeWVhcnMpICU+JQ0KICAgIGdyb3VwX2J5KHNjZW5hcmlvLCBzdWJzZWN0b3IsIHRlY2hub2xvZ3ksIHllYXIpICU+JQ0KICAgIHN1bW1hcmlzZSh2YWx1ZSA9IHN1bSh2YWx1ZSkpICU+JSB1bmdyb3VwKCkgJT4lIA0KICAgIHNlbGVjdChzY2VuYXJpbywgc291cmNlID0gdGVjaG5vbG9neSwgdGFyZ2V0ID0gc3Vic2VjdG9yLCB5ZWFyLCB2YWx1ZSkNCiAgLA0KICAjIGJyaWRnZSBnZW4gc2VjdG9yIHRvIGVsZWN0cmljaXR5IHN1cHBseSBzZWN0b3INCiAgZWxlY0dlbkJ5R2VuVGVjaENvb2xpbmdUZWNoICU+JQ0KICAgICMgc3VtIGJ5IHN1YnNlY3Rvcg0KICAgIGdyb3VwX2J5KHNjZW5hcmlvLCBzdWJzZWN0b3IsIG91dHB1dCwgeWVhcikgJT4lDQogICAgc3VtbWFyaXNlKHZhbHVlID0gc3VtKHZhbHVlKSkgJT4lIHVuZ3JvdXAoKSAlPiUNCiAgICByZW5hbWUoc291cmNlID0gc3Vic2VjdG9yLCB0YXJnZXQgPSBvdXRwdXQpIA0KICAsDQogICMgaW5wdXRzIHRvIHRoZSBlbmQgdXNlIHNlY3RvcnMNCiAgZWxlY1RESW5wdXRzT3V0cHV0cyAlPiUNCiAgICBmaWx0ZXIoZ3JlcGwoImVsZWN0XyIsIHNlY3RvcikpICU+JQ0KICAgIGdyb3VwX2J5KHNjZW5hcmlvLCBzZWN0b3IsIHllYXIpICU+JQ0KICAgIHN1bW1hcmlzZSh2YWx1ZSA9IHN1bSh2YWx1ZSkpICU+JSB1bmdyb3VwKCkgJT4lDQogICAgIyBUT0RPOiBhZGQgZWxlY3RyaWNpdHlfbmV0X293bnVzZSwgYW5kIGNyZWF0ZSBhIGxvc3NlcyAiZW5kLXVzZSINCiAgICBtdXRhdGUoc291cmNlID0gImVsZWN0cmljaXR5IikgJT4lDQogICAgc2VsZWN0KHNjZW5hcmlvLCBzb3VyY2UsIHRhcmdldCA9IHNlY3RvciwgeWVhciwgdmFsdWUpDQogICwNCiAgIyBlbGVjdHJpY2l0eSBjb25zdW1wdGlvbiBieSBkZW1hbmQgc2VjdG9yDQogIGVsZWNDb25zdW1wdGlvbkJ5RGVtYW5kU2VjdG9yICU+JQ0KICAgIGdyb3VwX2J5KHNjZW5hcmlvLCBzZWN0b3IsIGlucHV0LCB5ZWFyKSAlPiUNCiAgICBzdW1tYXJpc2UodmFsdWUgPSBzdW0odmFsdWUpKSAlPiUgdW5ncm91cCgpICU+JQ0KICAgIHNlbGVjdChzY2VuYXJpbywgc291cmNlID0gaW5wdXQsIHRhcmdldCA9IHNlY3RvciwgeWVhciwgdmFsdWUpDQopICU+JSBmaWx0ZXIoc291cmNlICE9IHRhcmdldCkNCmBgYA0KDQoNCmBgYHtyIGZpZy53aWR0aD0xMCwgd2FybmluZz1GQUxTRX0NCnBsb3Rfc2Fua2V5KGVsZWNfc291cmNlX3RhcmdldCwgIkVsZWN0cmljaXR5IEdlbmVyYXRpb24gYW5kIENvbnN1bXB0aW9uIikNCmBgYA0KDQoNCmBgYHtyIGZpZy53aWR0aD0xMCwgd2FybmluZz1GQUxTRX0NCiMgcmVtb3ZlIHdhdGVyIGZyb20gZWxlY3RyaWNpdHkgZGlhZ3JhbSANCnBsb3Rfc2Fua2V5KGVsZWNfc291cmNlX3RhcmdldCAlPiUgZmlsdGVyKHNvdXJjZSAhPSAid2F0ZXJfdGRfZWxlY19XIiksIHlyID0gMjA1MCwgIkVsZWN0cmljaXR5IEdlbmVyYXRpb24gYW5kIENvbnN1bXB0aW9uIikNCmBgYA0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0K